Skip to content

Commit

Permalink
avm2: Take a &mut StringContext in TObject::value_of
Browse files Browse the repository at this point in the history
(and as a consequence, also in `Value::as_{number, integer, u32}`)

This gives us access to the canonical empty string for use in
`Namespace::value_of`.
  • Loading branch information
moulins authored and torokati44 committed Oct 3, 2024
1 parent a51c76e commit 33d1f65
Show file tree
Hide file tree
Showing 17 changed files with 62 additions and 68 deletions.
6 changes: 3 additions & 3 deletions core/src/avm2/amf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub fn serialize_value<'gc>(
let int_vec: Vec<_> = vec
.iter()
.map(|v| {
v.as_integer(activation.context.gc_context)
v.as_integer(activation.strings())
.expect("Unexpected non-int value in int vector")
})
.collect();
Expand All @@ -91,7 +91,7 @@ pub fn serialize_value<'gc>(
let uint_vec: Vec<_> = vec
.iter()
.map(|v| {
v.as_u32(activation.context.gc_context)
v.as_u32(activation.strings())
.expect("Unexpected non-uint value in int vector")
})
.collect();
Expand All @@ -100,7 +100,7 @@ pub fn serialize_value<'gc>(
let num_vec: Vec<_> = vec
.iter()
.map(|v| {
v.as_number(activation.context.gc_context)
v.as_number(activation.strings())
.expect("Unexpected non-uint value in int vector")
})
.collect();
Expand Down
2 changes: 1 addition & 1 deletion core/src/avm2/globals/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ pub fn instance_init<'gc>(
if args.len() == 1 {
if let Some(expected_len) = args
.get(0)
.and_then(|v| v.as_number(activation.context.gc_context).ok())
.and_then(|v| v.as_number(activation.strings()).ok())
{
if expected_len < 0.0 || expected_len.is_nan() || expected_len.fract() != 0.0 {
return Err(Error::AvmError(range_error(
Expand Down
2 changes: 1 addition & 1 deletion core/src/avm2/globals/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ pub fn get_time<'gc>(
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this.as_date_object().unwrap();
this.value_of(activation.context.gc_context)
this.value_of(activation.strings())
}

/// Implements `setTime` method.
Expand Down
6 changes: 3 additions & 3 deletions core/src/avm2/globals/flash/display/graphics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1286,13 +1286,13 @@ fn read_point<'gc>(
let x = data
.get(*data_index, activation)
.ok()?
.as_number(activation.context.gc_context)
.as_number(activation.strings())
.expect("data is not a Vec.<Number>");

let y = data
.get(*data_index + 1, activation)
.ok()?
.as_number(activation.context.gc_context)
.as_number(activation.strings())
.expect("data is not a Vec.<Number>");

*data_index += 2;
Expand Down Expand Up @@ -1395,7 +1395,7 @@ fn process_commands<'gc>(
let command = commands
.get(i, activation)
.expect("missing command")
.as_integer(activation.context.gc_context)
.as_integer(activation.strings())
.expect("commands is not a Vec.<int>");

if process_command(activation, drawing, data, command, &mut data_index).is_none() {
Expand Down
13 changes: 6 additions & 7 deletions core/src/avm2/globals/flash/display/shader_job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,18 +107,18 @@ pub fn get_shader_args<'gc>(
let width = shader_input
.get_public_property("width", activation)
.unwrap()
.as_u32(activation.context.gc_context)
.as_u32(activation.strings())
.unwrap();
let height = shader_input
.get_public_property("height", activation)
.unwrap()
.as_u32(activation.context.gc_context)
.as_u32(activation.strings())
.unwrap();

let input_channels = shader_input
.get_public_property("channels", activation)
.unwrap()
.as_u32(activation.context.gc_context)
.as_u32(activation.strings())
.unwrap();

assert_eq!(*channels as u32, input_channels);
Expand Down Expand Up @@ -156,8 +156,7 @@ pub fn get_shader_args<'gc>(
bytes: vector
.iter()
.flat_map(|val| {
(val.as_number(activation.context.gc_context).unwrap()
as f32)
(val.as_number(activation.strings()).unwrap() as f32)
.to_le_bytes()
})
.collect(),
Expand Down Expand Up @@ -210,12 +209,12 @@ pub fn start<'gc>(

let output_width = this
.get_public_property("width", activation)?
.as_u32(activation.context.gc_context)
.as_u32(activation.strings())
.expect("ShaderJob.width is not a number");

let output_height = this
.get_public_property("height", activation)?
.as_u32(activation.context.gc_context)
.as_u32(activation.strings())
.expect("ShaderJob.height is not a number");

let pixel_bender_target = if let Some(bitmap) = target.as_bitmap_data() {
Expand Down
37 changes: 17 additions & 20 deletions core/src/avm2/globals/flash/display3D/context_3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,10 +365,7 @@ pub fn set_program_constants_from_vector<'gc>(

let raw_data = vector
.iter()
.map(|val| {
val.as_number(activation.context.gc_context)
.map(|val| val as f32)
})
.map(|val| val.as_number(activation.strings()).map(|val| val as f32))
.take(to_take)
.collect::<Result<Vec<f32>, _>>()?;

Expand All @@ -384,13 +381,13 @@ pub fn clear<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(context) = this.as_context_3d() {
// This is a native method, so all of the arguments have been checked and coerced for us
let red = args[0].as_number(activation.context.gc_context)?;
let green = args[1].as_number(activation.context.gc_context)?;
let blue = args[2].as_number(activation.context.gc_context)?;
let alpha = args[3].as_number(activation.context.gc_context)?;
let depth = args[4].as_number(activation.context.gc_context)?;
let stencil = args[5].as_integer(activation.context.gc_context)? as u32;
let mask = args[6].as_integer(activation.context.gc_context)? as u32;
let red = args[0].as_number(activation.strings())?;
let green = args[1].as_number(activation.strings())?;
let blue = args[2].as_number(activation.strings())?;
let alpha = args[3].as_number(activation.strings())?;
let depth = args[4].as_number(activation.strings())?;
let stencil = args[5].as_integer(activation.strings())? as u32;
let mask = args[6].as_integer(activation.strings())? as u32;
context.set_clear(red, green, blue, alpha, depth, stencil, mask);
}
Ok(Value::Undefined)
Expand All @@ -403,11 +400,11 @@ pub fn create_texture<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(context) = this.as_context_3d() {
// This is a native method, so all of the arguments have been checked and coerced for us
let width = args[0].as_integer(activation.context.gc_context)? as u32;
let height = args[1].as_integer(activation.context.gc_context)? as u32;
let width = args[0].as_integer(activation.strings())? as u32;
let height = args[1].as_integer(activation.strings())? as u32;
let format = args[2].coerce_to_string(activation)?;
let optimize_for_render_to_texture = args[3].coerce_to_boolean();
let streaming_levels = args[4].as_integer(activation.context.gc_context)? as u32;
let streaming_levels = args[4].as_integer(activation.strings())? as u32;
let format = Context3DTextureFormat::from_wstr(&format).ok_or_else(|| {
Error::RustError(
format!("Unsupported texture format in createTexture: {:?}", format).into(),
Expand Down Expand Up @@ -436,8 +433,8 @@ pub fn create_rectangle_texture<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(context) = this.as_context_3d() {
// This is a native method, so all of the arguments have been checked and coerced for us
let width = args[0].as_integer(activation.context.gc_context)? as u32;
let height = args[1].as_integer(activation.context.gc_context)? as u32;
let width = args[0].as_integer(activation.strings())? as u32;
let height = args[1].as_integer(activation.strings())? as u32;
let format = args[2].coerce_to_string(activation)?;
let optimize_for_render_to_texture = args[3].coerce_to_boolean();
let format = Context3DTextureFormat::from_wstr(&format).ok_or_else(|| {
Expand Down Expand Up @@ -472,10 +469,10 @@ pub fn create_cube_texture<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(context) = this.as_context_3d() {
// This is a native method, so all of the arguments have been checked and coerced for us
let size = args[0].as_integer(activation.context.gc_context)? as u32;
let size = args[0].as_integer(activation.strings())? as u32;
let format = args[1].coerce_to_string(activation)?;
let optimize_for_render_to_texture = args[2].coerce_to_boolean();
let streaming_levels = args[3].as_integer(activation.context.gc_context)? as u32;
let streaming_levels = args[3].as_integer(activation.strings())? as u32;
let format = Context3DTextureFormat::from_wstr(&format).ok_or_else(|| {
Error::RustError(
format!(
Expand Down Expand Up @@ -504,7 +501,7 @@ pub fn set_texture_at<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(context) = this.as_context_3d() {
// This is a native method, so all of the arguments have been checked and coerced for us
let sampler = args[0].as_integer(activation.context.gc_context)? as u32;
let sampler = args[0].as_integer(activation.strings())? as u32;
let mut cube = false;
let texture = if matches!(args[1], Value::Null) {
None
Expand Down Expand Up @@ -655,7 +652,7 @@ pub fn set_sampler_state_at<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(context) = this.as_context_3d() {
// This is a native method, so all of the arguments have been checked and coerced for us
let sampler = args[0].as_integer(activation.context.gc_context)? as u32;
let sampler = args[0].as_integer(activation.strings())? as u32;
let wrap = args[1].coerce_to_string(activation)?;
let filter = args[2].coerce_to_string(activation)?;
let mip_filter = args[3].coerce_to_string(activation)?;
Expand Down
2 changes: 1 addition & 1 deletion core/src/avm2/globals/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ pub fn stringify<'gc>(
}
} else {
let indent_size = spaces
.as_number(activation.context.gc_context)
.as_number(activation.strings())
.unwrap_or(0.0)
.clamp(0.0, 10.0) as u16;
if indent_size == 0 {
Expand Down
2 changes: 1 addition & 1 deletion core/src/avm2/globals/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ fn value_of<'gc>(
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
this.value_of(activation.context.gc_context)
this.value_of(activation.strings())
}

/// `Object.prototype.hasOwnProperty`
Expand Down
8 changes: 4 additions & 4 deletions core/src/avm2/globals/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ fn length<'gc>(
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Value::String(s) = this.value_of(activation.context.gc_context)? {
if let Value::String(s) = this.value_of(activation.strings())? {
return Ok(s.len().into());
}

Expand All @@ -116,7 +116,7 @@ fn char_at<'gc>(
this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Value::String(s) = this.value_of(activation.context.gc_context)? {
if let Value::String(s) = this.value_of(activation.strings())? {
// This function takes Number, so if we use coerce_to_i32 instead of coerce_to_number, the value may overflow.
let n = args
.get(0)
Expand Down Expand Up @@ -144,7 +144,7 @@ fn char_code_at<'gc>(
this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Value::String(s) = this.value_of(activation.context.gc_context)? {
if let Value::String(s) = this.value_of(activation.strings())? {
// This function takes Number, so if we use coerce_to_i32 instead of coerce_to_number, the value may overflow.
let n = args
.get(0)
Expand Down Expand Up @@ -634,7 +634,7 @@ fn value_of<'gc>(
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
this.value_of(activation.context.gc_context)
this.value_of(activation.strings())
}

/// Implements `String.toUpperCase`
Expand Down
4 changes: 2 additions & 2 deletions core/src/avm2/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::bitmap::bitmap_data::BitmapDataWrapper;
use crate::display_object::DisplayObject;
use crate::html::TextFormat;
use crate::streams::NetStream;
use crate::string::AvmString;
use crate::string::{AvmString, StringContext};
use gc_arena::{Collect, Gc, Mutation};
use ruffle_macros::enum_trait_object;
use std::cell::{Ref, RefMut};
Expand Down Expand Up @@ -990,7 +990,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
///
/// The default implementation wraps the object in a `Value`, using the
/// `Into<Object<'gc>>` implementation.
fn value_of(&self, _mc: &Mutation<'gc>) -> Result<Value<'gc>, Error<'gc>> {
fn value_of(&self, _context: &mut StringContext<'gc>) -> Result<Value<'gc>, Error<'gc>> {
Ok(Value::Object((*self).into()))
}

Expand Down
5 changes: 3 additions & 2 deletions core/src/avm2/object/date_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject};
use crate::avm2::value::{Hint, Value};
use crate::avm2::Error;
use crate::string::StringContext;
use chrono::{DateTime, Utc};
use core::fmt;
use gc_arena::{Collect, Gc, GcWeak, Mutation};
use gc_arena::{Collect, Gc, GcWeak};
use std::cell::Cell;

/// A class instance allocator that allocates Date objects.
Expand Down Expand Up @@ -96,7 +97,7 @@ impl<'gc> TObject<'gc> for DateObject<'gc> {
Gc::as_ptr(self.0) as *const ObjectPtr
}

fn value_of(&self, _mc: &Mutation<'gc>) -> Result<Value<'gc>, Error<'gc>> {
fn value_of(&self, _context: &mut StringContext<'gc>) -> Result<Value<'gc>, Error<'gc>> {
if let Some(date) = self.date_time() {
Ok((date.timestamp_millis() as f64).into())
} else {
Expand Down
3 changes: 2 additions & 1 deletion core/src/avm2/object/dispatch_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::string::StringContext;
use core::fmt;
use gc_arena::barrier::unlock;
use gc_arena::{lock::RefLock, Collect, Gc, GcWeak, Mutation};
Expand Down Expand Up @@ -104,7 +105,7 @@ impl<'gc> TObject<'gc> for DispatchObject<'gc> {
Err("Cannot construct internal event dispatcher structures.".into())
}

fn value_of(&self, _mc: &Mutation<'gc>) -> Result<Value<'gc>, Error<'gc>> {
fn value_of(&self, _context: &mut StringContext<'gc>) -> Result<Value<'gc>, Error<'gc>> {
Err("Cannot subclass internal event dispatcher structures.".into())
}

Expand Down
10 changes: 3 additions & 7 deletions core/src/avm2/object/namespace_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject};
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::avm2::Namespace;
use crate::string::AvmString;
use crate::string::{AvmString, StringContext};
use core::fmt;
use gc_arena::barrier::unlock;
use gc_arena::{lock::Lock, Collect, Gc, GcWeak, Mutation};
Expand Down Expand Up @@ -123,12 +123,8 @@ impl<'gc> TObject<'gc> for NamespaceObject<'gc> {
Gc::as_ptr(self.0) as *const ObjectPtr
}

fn value_of(&self, _mc: &Mutation<'gc>) -> Result<Value<'gc>, Error<'gc>> {
// TODO(moulins): pass in a StringContext so we can call .as_uri() directly.
match self.0.namespace.get().as_uri_opt() {
Some(uri) => Ok(uri.into()),
None => Ok("".into()),
}
fn value_of(&self, context: &mut StringContext<'gc>) -> Result<Value<'gc>, Error<'gc>> {
Ok(self.0.namespace.get().as_uri(context).into())
}

fn as_namespace(&self) -> Option<Namespace<'gc>> {
Expand Down
4 changes: 2 additions & 2 deletions core/src/avm2/object/primitive_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject};
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::string::AvmString;
use crate::string::{AvmString, StringContext};
use gc_arena::barrier::unlock;
use gc_arena::{lock::RefLock, Collect, Gc, GcWeak, Mutation};

Expand Down Expand Up @@ -142,7 +142,7 @@ impl<'gc> TObject<'gc> for PrimitiveObject<'gc> {
}
}

fn value_of(&self, _mc: &Mutation<'gc>) -> Result<Value<'gc>, Error<'gc>> {
fn value_of(&self, _context: &mut StringContext<'gc>) -> Result<Value<'gc>, Error<'gc>> {
Ok(*self.0.primitive.borrow())
}

Expand Down
6 changes: 3 additions & 3 deletions core/src/avm2/object/regexp_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject};
use crate::avm2::regexp::{RegExp, RegExpFlags};
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::string::{AvmString, WString};
use crate::string::{AvmString, StringContext, WString};
use core::fmt;
use gc_arena::barrier::unlock;
use gc_arena::{lock::RefLock, Collect, Gc, GcWeak, Mutation};
Expand Down Expand Up @@ -95,7 +95,7 @@ impl<'gc> TObject<'gc> for RegExpObject<'gc> {
Gc::as_ptr(self.0) as *const ObjectPtr
}

fn value_of(&self, mc: &Mutation<'gc>) -> Result<Value<'gc>, Error<'gc>> {
fn value_of(&self, context: &mut StringContext<'gc>) -> Result<Value<'gc>, Error<'gc>> {
let regexp = self.0.regexp.borrow();
let mut s = WString::new();
s.push_byte(b'/');
Expand All @@ -120,7 +120,7 @@ impl<'gc> TObject<'gc> for RegExpObject<'gc> {
s.push_byte(b'x');
}

Ok(AvmString::new(mc, s).into())
Ok(AvmString::new(context.gc(), s).into())
}

/// Unwrap this object as a regexp.
Expand Down
Loading

0 comments on commit 33d1f65

Please sign in to comment.