blob: c979849ddcd535b133f0589f086bbdc79b1ad9c9 [file] [log] [blame]
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001// Copyright 2010 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000043#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000045#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000046#include "liveobjectlist-inl.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000047#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048#include "platform.h"
49#include "runtime.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050#include "runtime-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000052#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000053#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000054#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000055#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056
kasperl@chromium.org71affb52009-05-26 05:44:31 +000057namespace v8 {
58namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059
60
ager@chromium.org3e875802009-06-29 08:26:34 +000061#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000062 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
64// Cast the given object to a value of the specified type and store
65// it in a variable with the given name. If the object is not of the
66// expected type call IllegalOperation and return.
67#define CONVERT_CHECKED(Type, name, obj) \
68 RUNTIME_ASSERT(obj->Is##Type()); \
69 Type* name = Type::cast(obj);
70
71#define CONVERT_ARG_CHECKED(Type, name, index) \
72 RUNTIME_ASSERT(args[index]->Is##Type()); \
73 Handle<Type> name = args.at<Type>(index);
74
kasper.lundbd3ec4e2008-07-09 11:06:54 +000075// Cast the given object to a boolean and store it in a variable with
76// the given name. If the object is not a boolean call IllegalOperation
77// and return.
78#define CONVERT_BOOLEAN_CHECKED(name, obj) \
79 RUNTIME_ASSERT(obj->IsBoolean()); \
80 bool name = (obj)->IsTrue();
81
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000082// Cast the given object to a Smi and store its value in an int variable
83// with the given name. If the object is not a Smi call IllegalOperation
84// and return.
85#define CONVERT_SMI_CHECKED(name, obj) \
86 RUNTIME_ASSERT(obj->IsSmi()); \
87 int name = Smi::cast(obj)->value();
88
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000089// Cast the given object to a double and store it in a variable with
90// the given name. If the object is not a number (as opposed to
91// the number not-a-number) call IllegalOperation and return.
92#define CONVERT_DOUBLE_CHECKED(name, obj) \
93 RUNTIME_ASSERT(obj->IsNumber()); \
94 double name = (obj)->Number();
95
96// Call the specified converter on the object *comand store the result in
97// a variable of the specified type with the given name. If the
98// object is not a Number call IllegalOperation and return.
99#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
100 RUNTIME_ASSERT(obj->IsNumber()); \
101 type name = NumberTo##Type(obj);
102
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000104MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
105 JSObject* boilerplate) {
106 StackLimitCheck check(isolate);
107 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000109 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000110 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000111 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000112 if (!maybe_result->ToObject(&result)) return maybe_result;
113 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000114 JSObject* copy = JSObject::cast(result);
115
116 // Deep copy local properties.
117 if (copy->HasFastProperties()) {
118 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000119 for (int i = 0; i < properties->length(); i++) {
120 Object* value = properties->get(i);
121 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000122 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000123 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000124 if (!maybe_result->ToObject(&result)) return maybe_result;
125 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000126 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000127 }
128 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000129 int nof = copy->map()->inobject_properties();
130 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000131 Object* value = copy->InObjectPropertyAt(i);
132 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000133 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000134 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000135 if (!maybe_result->ToObject(&result)) return maybe_result;
136 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000138 }
139 }
140 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000141 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000142 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000143 if (!maybe_result->ToObject(&result)) return maybe_result;
144 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000145 FixedArray* names = FixedArray::cast(result);
146 copy->GetLocalPropertyNames(names, 0);
147 for (int i = 0; i < names->length(); i++) {
148 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000149 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000150 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000151 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000152 // Only deep copy fields from the object literal expression.
153 // In particular, don't try to copy the length attribute of
154 // an array.
155 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000156 Object* value =
157 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000158 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000159 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
163 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000164 // Creating object copy for literals. No strict mode needed.
165 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000166 if (!maybe_result->ToObject(&result)) return maybe_result;
167 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000168 }
169 }
170 }
171
172 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000173 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000174 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000175 switch (copy->GetElementsKind()) {
176 case JSObject::FAST_ELEMENTS: {
177 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000178 if (elements->map() == heap->fixed_cow_array_map()) {
179 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000180#ifdef DEBUG
181 for (int i = 0; i < elements->length(); i++) {
182 ASSERT(!elements->get(i)->IsJSObject());
183 }
184#endif
185 } else {
186 for (int i = 0; i < elements->length(); i++) {
187 Object* value = elements->get(i);
188 if (value->IsJSObject()) {
189 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000190 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
191 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000192 if (!maybe_result->ToObject(&result)) return maybe_result;
193 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000194 elements->set(i, result);
195 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000196 }
197 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000198 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000199 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000200 case JSObject::DICTIONARY_ELEMENTS: {
201 NumberDictionary* element_dictionary = copy->element_dictionary();
202 int capacity = element_dictionary->Capacity();
203 for (int i = 0; i < capacity; i++) {
204 Object* k = element_dictionary->KeyAt(i);
205 if (element_dictionary->IsKey(k)) {
206 Object* value = element_dictionary->ValueAt(i);
207 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000208 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000209 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
210 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000211 if (!maybe_result->ToObject(&result)) return maybe_result;
212 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000213 element_dictionary->ValueAtPut(i, result);
214 }
215 }
216 }
217 break;
218 }
219 default:
220 UNREACHABLE();
221 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000222 }
223 return copy;
224}
225
226
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000227static MaybeObject* Runtime_CloneLiteralBoilerplate(
228 RUNTIME_CALLING_CONVENTION) {
229 RUNTIME_GET_ISOLATE;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000230 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000231 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000232}
233
234
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000235static MaybeObject* Runtime_CloneShallowLiteralBoilerplate(
236 RUNTIME_CALLING_CONVENTION) {
237 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000238 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000239 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000240}
241
242
ager@chromium.org236ad962008-09-25 09:45:57 +0000243static Handle<Map> ComputeObjectLiteralMap(
244 Handle<Context> context,
245 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000246 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000247 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000248 int properties_length = constant_properties->length();
249 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000250 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000251 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000252 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000253 for (int p = 0; p != properties_length; p += 2) {
254 Object* key = constant_properties->get(p);
255 uint32_t element_index = 0;
256 if (key->IsSymbol()) {
257 number_of_symbol_keys++;
258 } else if (key->ToArrayIndex(&element_index)) {
259 // An index key does not require space in the property backing store.
260 number_of_properties--;
261 } else {
262 // Bail out as a non-symbol non-index key makes caching impossible.
263 // ASSERT to make sure that the if condition after the loop is false.
264 ASSERT(number_of_symbol_keys != number_of_properties);
265 break;
266 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000267 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000268 // If we only have symbols and array indices among keys then we can
269 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000270 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000271 if ((number_of_symbol_keys == number_of_properties) &&
272 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000273 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000274 Handle<FixedArray> keys =
275 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000276 if (number_of_symbol_keys > 0) {
277 int index = 0;
278 for (int p = 0; p < properties_length; p += 2) {
279 Object* key = constant_properties->get(p);
280 if (key->IsSymbol()) {
281 keys->set(index++, key);
282 }
283 }
284 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000285 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000286 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000287 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000288 }
289 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000290 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000291 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000292 Handle<Map>(context->object_function()->initial_map()),
293 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000294}
295
296
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000297static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000298 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000299 Handle<FixedArray> literals,
300 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000301
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000302
303static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000304 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000305 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000306 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000307 bool should_have_fast_elements,
308 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000309 // Get the global context from the literals array. This is the
310 // context in which the function was created and we use the object
311 // function from this context to create the object literal. We do
312 // not use the object function from the current global context
313 // because this might be the object function from another context
314 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000315 Handle<Context> context =
316 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
317
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000318 // In case we have function literals, we want the object to be in
319 // slow properties mode for now. We don't go in the map cache because
320 // maps with constant functions can't be shared if the functions are
321 // not the same (which is the common case).
322 bool is_result_from_cache = false;
323 Handle<Map> map = has_function_literal
324 ? Handle<Map>(context->object_function()->initial_map())
325 : ComputeObjectLiteralMap(context,
326 constant_properties,
327 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000328
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000329 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000330
331 // Normalize the elements of the boilerplate to save space if needed.
332 if (!should_have_fast_elements) NormalizeElements(boilerplate);
333
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000334 // Add the constant properties to the boilerplate.
335 int length = constant_properties->length();
336 bool should_transform =
337 !is_result_from_cache && boilerplate->HasFastProperties();
338 if (should_transform || has_function_literal) {
339 // Normalize the properties of object to avoid n^2 behavior
340 // when extending the object multiple properties. Indicate the number of
341 // properties to be added.
342 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
343 }
344
345 for (int index = 0; index < length; index +=2) {
346 Handle<Object> key(constant_properties->get(index+0), isolate);
347 Handle<Object> value(constant_properties->get(index+1), isolate);
348 if (value->IsFixedArray()) {
349 // The value contains the constant_properties of a
350 // simple object or array literal.
351 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
352 value = CreateLiteralBoilerplate(isolate, literals, array);
353 if (value.is_null()) return value;
354 }
355 Handle<Object> result;
356 uint32_t element_index = 0;
357 if (key->IsSymbol()) {
358 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
359 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000360 result = SetOwnElement(boilerplate,
361 element_index,
362 value,
363 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000364 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000365 Handle<String> name(String::cast(*key));
366 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000367 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
368 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000369 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000370 } else if (key->ToArrayIndex(&element_index)) {
371 // Array index (uint32).
372 result = SetOwnElement(boilerplate,
373 element_index,
374 value,
375 kNonStrictMode);
376 } else {
377 // Non-uint32 number.
378 ASSERT(key->IsNumber());
379 double num = key->Number();
380 char arr[100];
381 Vector<char> buffer(arr, ARRAY_SIZE(arr));
382 const char* str = DoubleToCString(num, buffer);
383 Handle<String> name =
384 isolate->factory()->NewStringFromAscii(CStrVector(str));
385 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
386 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000387 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000388 // If setting the property on the boilerplate throws an
389 // exception, the exception is converted to an empty handle in
390 // the handle based operations. In that case, we need to
391 // convert back to an exception.
392 if (result.is_null()) return result;
393 }
394
395 // Transform to fast properties if necessary. For object literals with
396 // containing function literals we defer this operation until after all
397 // computed properties have been assigned so that we can generate
398 // constant function properties.
399 if (should_transform && !has_function_literal) {
400 TransformToFastProperties(boilerplate,
401 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000402 }
403
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000404 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000405}
406
407
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000408static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000409 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000410 Handle<FixedArray> literals,
411 Handle<FixedArray> elements) {
412 // Create the JSArray.
413 Handle<JSFunction> constructor(
414 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000416
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000417 const bool is_cow =
418 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000419 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000420 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000421
422 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000423 if (is_cow) {
424#ifdef DEBUG
425 // Copy-on-write arrays must be shallow (and simple).
426 for (int i = 0; i < content->length(); i++) {
427 ASSERT(!content->get(i)->IsFixedArray());
428 }
429#endif
430 } else {
431 for (int i = 0; i < content->length(); i++) {
432 if (content->get(i)->IsFixedArray()) {
433 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000434 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000435 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
436 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000437 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000438 if (result.is_null()) return result;
439 content->set(i, *result);
440 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000441 }
442 }
443
444 // Set the elements.
445 Handle<JSArray>::cast(object)->SetContent(*content);
446 return object;
447}
448
449
450static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000451 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000452 Handle<FixedArray> literals,
453 Handle<FixedArray> array) {
454 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000455 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000456 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000457 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000458 return CreateObjectLiteralBoilerplate(isolate,
459 literals,
460 elements,
461 true,
462 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000463 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000464 return CreateObjectLiteralBoilerplate(isolate,
465 literals,
466 elements,
467 false,
468 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000469 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000470 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000471 default:
472 UNREACHABLE();
473 return Handle<Object>::null();
474 }
475}
476
477
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000478static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(
479 RUNTIME_CALLING_CONVENTION) {
480 RUNTIME_GET_ISOLATE;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000481 // Takes a FixedArray of elements containing the literal elements of
482 // the array literal and produces JSArray with those elements.
483 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000484 // which contains the context from which to get the Array function
485 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000486 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000487 ASSERT(args.length() == 3);
488 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
489 CONVERT_SMI_CHECKED(literals_index, args[1]);
490 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000492 Handle<Object> object =
493 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000494 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000495
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000496 // Update the functions literal and return the boilerplate.
497 literals->set(literals_index, *object);
498 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000499}
500
501
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000502static MaybeObject* Runtime_CreateObjectLiteral(RUNTIME_CALLING_CONVENTION) {
503 RUNTIME_GET_ISOLATE;
504 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000505 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000506 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
507 CONVERT_SMI_CHECKED(literals_index, args[1]);
508 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000509 CONVERT_SMI_CHECKED(flags, args[3]);
510 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
511 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000512
513 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000514 Handle<Object> boilerplate(literals->get(literals_index), isolate);
515 if (*boilerplate == isolate->heap()->undefined_value()) {
516 boilerplate = CreateObjectLiteralBoilerplate(isolate,
517 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000518 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000519 should_have_fast_elements,
520 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000521 if (boilerplate.is_null()) return Failure::Exception();
522 // Update the functions literal and return the boilerplate.
523 literals->set(literals_index, *boilerplate);
524 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000526}
527
528
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000529static MaybeObject* Runtime_CreateObjectLiteralShallow(
530 RUNTIME_CALLING_CONVENTION) {
531 RUNTIME_GET_ISOLATE;
532 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000533 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000534 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
535 CONVERT_SMI_CHECKED(literals_index, args[1]);
536 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000537 CONVERT_SMI_CHECKED(flags, args[3]);
538 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
539 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000540
541 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000542 Handle<Object> boilerplate(literals->get(literals_index), isolate);
543 if (*boilerplate == isolate->heap()->undefined_value()) {
544 boilerplate = CreateObjectLiteralBoilerplate(isolate,
545 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000546 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000547 should_have_fast_elements,
548 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000549 if (boilerplate.is_null()) return Failure::Exception();
550 // Update the functions literal and return the boilerplate.
551 literals->set(literals_index, *boilerplate);
552 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000553 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000554}
555
556
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000557static MaybeObject* Runtime_CreateArrayLiteral(RUNTIME_CALLING_CONVENTION) {
558 RUNTIME_GET_ISOLATE;
559 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000560 ASSERT(args.length() == 3);
561 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
562 CONVERT_SMI_CHECKED(literals_index, args[1]);
563 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
564
565 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000566 Handle<Object> boilerplate(literals->get(literals_index), isolate);
567 if (*boilerplate == isolate->heap()->undefined_value()) {
568 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000569 if (boilerplate.is_null()) return Failure::Exception();
570 // Update the functions literal and return the boilerplate.
571 literals->set(literals_index, *boilerplate);
572 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000573 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000574}
575
576
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577static MaybeObject* Runtime_CreateArrayLiteralShallow(
578 RUNTIME_CALLING_CONVENTION) {
579 RUNTIME_GET_ISOLATE;
580 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000581 ASSERT(args.length() == 3);
582 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
583 CONVERT_SMI_CHECKED(literals_index, args[1]);
584 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
585
586 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000587 Handle<Object> boilerplate(literals->get(literals_index), isolate);
588 if (*boilerplate == isolate->heap()->undefined_value()) {
589 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000590 if (boilerplate.is_null()) return Failure::Exception();
591 // Update the functions literal and return the boilerplate.
592 literals->set(literals_index, *boilerplate);
593 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000594 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000595 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000596 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000597 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000598 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000599}
600
601
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602static MaybeObject* Runtime_CreateCatchExtensionObject(
603 RUNTIME_CALLING_CONVENTION) {
604 RUNTIME_GET_ISOLATE;
ager@chromium.org32912102009-01-16 10:38:43 +0000605 ASSERT(args.length() == 2);
606 CONVERT_CHECKED(String, key, args[0]);
607 Object* value = args[1];
608 // Create a catch context extension object.
609 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000610 isolate->context()->global_context()->
611 context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000612 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000613 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000614 if (!maybe_object->ToObject(&object)) return maybe_object;
615 }
ager@chromium.org32912102009-01-16 10:38:43 +0000616 // Assign the exception value to the catch variable and make sure
617 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000618 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000619 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
620 JSObject::cast(object)->SetProperty(
621 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000622 if (!maybe_value->ToObject(&value)) return maybe_value;
623 }
ager@chromium.org32912102009-01-16 10:38:43 +0000624 return object;
625}
626
627
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000628static MaybeObject* Runtime_ClassOf(RUNTIME_CALLING_CONVENTION) {
629 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000630 NoHandleAllocation ha;
631 ASSERT(args.length() == 1);
632 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000633 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000634 return JSObject::cast(obj)->class_name();
635}
636
ager@chromium.org7c537e22008-10-16 08:43:32 +0000637
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000638static MaybeObject* Runtime_IsInPrototypeChain(RUNTIME_CALLING_CONVENTION) {
639 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640 NoHandleAllocation ha;
641 ASSERT(args.length() == 2);
642 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
643 Object* O = args[0];
644 Object* V = args[1];
645 while (true) {
646 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 if (prototype->IsNull()) return isolate->heap()->false_value();
648 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649 V = prototype;
650 }
651}
652
653
ager@chromium.org9085a012009-05-11 19:22:57 +0000654// Inserts an object as the hidden prototype of another object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000655static MaybeObject* Runtime_SetHiddenPrototype(RUNTIME_CALLING_CONVENTION) {
656 RUNTIME_GET_ISOLATE;
ager@chromium.org9085a012009-05-11 19:22:57 +0000657 NoHandleAllocation ha;
658 ASSERT(args.length() == 2);
659 CONVERT_CHECKED(JSObject, jsobject, args[0]);
660 CONVERT_CHECKED(JSObject, proto, args[1]);
661
662 // Sanity checks. The old prototype (that we are replacing) could
663 // theoretically be null, but if it is not null then check that we
664 // didn't already install a hidden prototype here.
665 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
666 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
667 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
668
669 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000670 Object* map_or_failure;
671 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
672 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
673 return maybe_map_or_failure;
674 }
675 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000676 Map* new_proto_map = Map::cast(map_or_failure);
677
lrn@chromium.org303ada72010-10-27 09:33:13 +0000678 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
679 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
680 return maybe_map_or_failure;
681 }
682 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000683 Map* new_map = Map::cast(map_or_failure);
684
685 // Set proto's prototype to be the old prototype of the object.
686 new_proto_map->set_prototype(jsobject->GetPrototype());
687 proto->set_map(new_proto_map);
688 new_proto_map->set_is_hidden_prototype();
689
690 // Set the object's prototype to proto.
691 new_map->set_prototype(proto);
692 jsobject->set_map(new_map);
693
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000694 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000695}
696
697
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000698static MaybeObject* Runtime_IsConstructCall(RUNTIME_CALLING_CONVENTION) {
699 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000700 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000701 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000702 JavaScriptFrameIterator it;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000703 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000704}
705
706
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000707// Recursively traverses hidden prototypes if property is not found
708static void GetOwnPropertyImplementation(JSObject* obj,
709 String* name,
710 LookupResult* result) {
711 obj->LocalLookupRealNamedProperty(name, result);
712
713 if (!result->IsProperty()) {
714 Object* proto = obj->GetPrototype();
715 if (proto->IsJSObject() &&
716 JSObject::cast(proto)->map()->is_hidden_prototype())
717 GetOwnPropertyImplementation(JSObject::cast(proto),
718 name, result);
719 }
720}
721
722
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000723static bool CheckAccessException(LookupResult* result,
724 v8::AccessType access_type) {
725 if (result->type() == CALLBACKS) {
726 Object* callback = result->GetCallbackObject();
727 if (callback->IsAccessorInfo()) {
728 AccessorInfo* info = AccessorInfo::cast(callback);
729 bool can_access =
730 (access_type == v8::ACCESS_HAS &&
731 (info->all_can_read() || info->all_can_write())) ||
732 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
733 (access_type == v8::ACCESS_SET && info->all_can_write());
734 return can_access;
735 }
736 }
737
738 return false;
739}
740
741
742static bool CheckAccess(JSObject* obj,
743 String* name,
744 LookupResult* result,
745 v8::AccessType access_type) {
746 ASSERT(result->IsProperty());
747
748 JSObject* holder = result->holder();
749 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000750 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000751 while (true) {
752 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000753 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000754 // Access check callback denied the access, but some properties
755 // can have a special permissions which override callbacks descision
756 // (currently see v8::AccessControl).
757 break;
758 }
759
760 if (current == holder) {
761 return true;
762 }
763
764 current = JSObject::cast(current->GetPrototype());
765 }
766
767 // API callbacks can have per callback access exceptions.
768 switch (result->type()) {
769 case CALLBACKS: {
770 if (CheckAccessException(result, access_type)) {
771 return true;
772 }
773 break;
774 }
775 case INTERCEPTOR: {
776 // If the object has an interceptor, try real named properties.
777 // Overwrite the result to fetch the correct property later.
778 holder->LookupRealNamedProperty(name, result);
779 if (result->IsProperty()) {
780 if (CheckAccessException(result, access_type)) {
781 return true;
782 }
783 }
784 break;
785 }
786 default:
787 break;
788 }
789
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000790 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000791 return false;
792}
793
794
795// TODO(1095): we should traverse hidden prototype hierachy as well.
796static bool CheckElementAccess(JSObject* obj,
797 uint32_t index,
798 v8::AccessType access_type) {
799 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000800 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000801 return false;
802 }
803
804 return true;
805}
806
807
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000808// Enumerator used as indices into the array returned from GetOwnProperty
809enum PropertyDescriptorIndices {
810 IS_ACCESSOR_INDEX,
811 VALUE_INDEX,
812 GETTER_INDEX,
813 SETTER_INDEX,
814 WRITABLE_INDEX,
815 ENUMERABLE_INDEX,
816 CONFIGURABLE_INDEX,
817 DESCRIPTOR_SIZE
818};
819
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000820// Returns an array with the property description:
821// if args[1] is not a property on args[0]
822// returns undefined
823// if args[1] is a data property on args[0]
824// [false, value, Writeable, Enumerable, Configurable]
825// if args[1] is an accessor on args[0]
826// [true, GetFunction, SetFunction, Enumerable, Configurable]
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000827static MaybeObject* Runtime_GetOwnProperty(RUNTIME_CALLING_CONVENTION) {
828 RUNTIME_GET_ISOLATE;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000829 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000830 Heap* heap = isolate->heap();
831 HandleScope scope(isolate);
832 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
833 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000834 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000835 CONVERT_ARG_CHECKED(JSObject, obj, 0);
836 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000837
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000838 // This could be an element.
839 uint32_t index;
840 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000841 switch (obj->HasLocalElement(index)) {
842 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000843 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000844
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000845 case JSObject::STRING_CHARACTER_ELEMENT: {
846 // Special handling of string objects according to ECMAScript 5
847 // 15.5.5.2. Note that this might be a string object with elements
848 // other than the actual string value. This is covered by the
849 // subsequent cases.
850 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
851 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000852 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000853
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000854 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000855 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000856 elms->set(WRITABLE_INDEX, heap->false_value());
857 elms->set(ENUMERABLE_INDEX, heap->false_value());
858 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000859 return *desc;
860 }
861
862 case JSObject::INTERCEPTED_ELEMENT:
863 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000864 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000865 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000866 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000867 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000868 elms->set(WRITABLE_INDEX, heap->true_value());
869 elms->set(ENUMERABLE_INDEX, heap->true_value());
870 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000871 return *desc;
872 }
873
874 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000875 Handle<JSObject> holder = obj;
876 if (obj->IsJSGlobalProxy()) {
877 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000878 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000879 ASSERT(proto->IsJSGlobalObject());
880 holder = Handle<JSObject>(JSObject::cast(proto));
881 }
882 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000883 int entry = dictionary->FindEntry(index);
884 ASSERT(entry != NumberDictionary::kNotFound);
885 PropertyDetails details = dictionary->DetailsAt(entry);
886 switch (details.type()) {
887 case CALLBACKS: {
888 // This is an accessor property with getter and/or setter.
889 FixedArray* callbacks =
890 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000891 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000892 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
893 elms->set(GETTER_INDEX, callbacks->get(0));
894 }
895 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
896 elms->set(SETTER_INDEX, callbacks->get(1));
897 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000898 break;
899 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000900 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000901 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000902 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000903 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000904 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000905 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000906 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000907 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000908 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000909 default:
910 UNREACHABLE();
911 break;
912 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000913 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
914 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000915 return *desc;
916 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000917 }
918 }
919
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000920 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000921 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000922
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000923 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000924 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000925 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000926
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000927 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000929 }
930
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
932 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000933
934 bool is_js_accessor = (result.type() == CALLBACKS) &&
935 (result.GetCallbackObject()->IsFixedArray());
936
937 if (is_js_accessor) {
938 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000939 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000940
941 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
942 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
943 elms->set(GETTER_INDEX, structure->get(0));
944 }
945 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
946 elms->set(SETTER_INDEX, structure->get(1));
947 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000948 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000949 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
950 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000951
952 PropertyAttributes attrs;
953 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000954 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000955 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
956 if (!maybe_value->ToObject(&value)) return maybe_value;
957 }
958 elms->set(VALUE_INDEX, value);
959 }
960
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000961 return *desc;
962}
963
964
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000965static MaybeObject* Runtime_PreventExtensions(RUNTIME_CALLING_CONVENTION) {
966 RUNTIME_GET_ISOLATE;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000967 ASSERT(args.length() == 1);
968 CONVERT_CHECKED(JSObject, obj, args[0]);
969 return obj->PreventExtensions();
970}
971
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000972
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000973static MaybeObject* Runtime_IsExtensible(RUNTIME_CALLING_CONVENTION) {
974 RUNTIME_GET_ISOLATE;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000975 ASSERT(args.length() == 1);
976 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000977 if (obj->IsJSGlobalProxy()) {
978 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000979 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000980 ASSERT(proto->IsJSGlobalObject());
981 obj = JSObject::cast(proto);
982 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 return obj->map()->is_extensible() ? isolate->heap()->true_value()
984 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000985}
986
987
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000988static MaybeObject* Runtime_RegExpCompile(RUNTIME_CALLING_CONVENTION) {
989 RUNTIME_GET_ISOLATE;
990 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000992 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
993 CONVERT_ARG_CHECKED(String, pattern, 1);
994 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000995 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
996 if (result.is_null()) return Failure::Exception();
997 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998}
999
1000
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001001static MaybeObject* Runtime_CreateApiFunction(RUNTIME_CALLING_CONVENTION) {
1002 RUNTIME_GET_ISOLATE;
1003 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001004 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001005 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001006 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007}
1008
1009
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001010static MaybeObject* Runtime_IsTemplate(RUNTIME_CALLING_CONVENTION) {
1011 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012 ASSERT(args.length() == 1);
1013 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001014 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001015 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001016}
1017
1018
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001019static MaybeObject* Runtime_GetTemplateField(RUNTIME_CALLING_CONVENTION) {
1020 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001021 ASSERT(args.length() == 2);
1022 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001023 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001024 int index = field->value();
1025 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1026 InstanceType type = templ->map()->instance_type();
1027 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1028 type == OBJECT_TEMPLATE_INFO_TYPE);
1029 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001030 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001031 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1032 } else {
1033 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1034 }
1035 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001036}
1037
1038
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001039static MaybeObject* Runtime_DisableAccessChecks(RUNTIME_CALLING_CONVENTION) {
1040 RUNTIME_GET_ISOLATE;
ager@chromium.org870a0b62008-11-04 11:43:05 +00001041 ASSERT(args.length() == 1);
1042 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001043 Map* old_map = object->map();
1044 bool needs_access_checks = old_map->is_access_check_needed();
1045 if (needs_access_checks) {
1046 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001047 Object* new_map;
1048 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1049 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1050 }
ager@chromium.org32912102009-01-16 10:38:43 +00001051
1052 Map::cast(new_map)->set_is_access_check_needed(false);
1053 object->set_map(Map::cast(new_map));
1054 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001055 return needs_access_checks ? isolate->heap()->true_value()
1056 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001057}
1058
1059
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060static MaybeObject* Runtime_EnableAccessChecks(RUNTIME_CALLING_CONVENTION) {
1061 RUNTIME_GET_ISOLATE;
ager@chromium.org870a0b62008-11-04 11:43:05 +00001062 ASSERT(args.length() == 1);
1063 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001064 Map* old_map = object->map();
1065 if (!old_map->is_access_check_needed()) {
1066 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001067 Object* new_map;
1068 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1069 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1070 }
ager@chromium.org32912102009-01-16 10:38:43 +00001071
1072 Map::cast(new_map)->set_is_access_check_needed(true);
1073 object->set_map(Map::cast(new_map));
1074 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001075 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001076}
1077
1078
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001079static Failure* ThrowRedeclarationError(Isolate* isolate,
1080 const char* type,
1081 Handle<String> name) {
1082 HandleScope scope(isolate);
1083 Handle<Object> type_handle =
1084 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001085 Handle<Object> args[2] = { type_handle, name };
1086 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001087 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1088 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001089}
1090
1091
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001092static MaybeObject* Runtime_DeclareGlobals(RUNTIME_CALLING_CONVENTION) {
1093 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001094 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001095 HandleScope scope(isolate);
1096 Handle<GlobalObject> global = Handle<GlobalObject>(
1097 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098
ager@chromium.org3811b432009-10-28 14:53:37 +00001099 Handle<Context> context = args.at<Context>(0);
1100 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001101 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001102 StrictModeFlag strict_mode =
1103 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1104 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001105
1106 // Compute the property attributes. According to ECMA-262, section
1107 // 13, page 71, the property must be read-only and
1108 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1109 // property as read-only, so we don't either.
1110 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1111
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001112 // Traverse the name/value pairs and set the properties.
1113 int length = pairs->length();
1114 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001115 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001116 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001117 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118
1119 // We have to declare a global const property. To capture we only
1120 // assign to it when evaluating the assignment for "const x =
1121 // <expr>" the initial value is the hole.
1122 bool is_const_property = value->IsTheHole();
1123
1124 if (value->IsUndefined() || is_const_property) {
1125 // Lookup the property in the global object, and don't set the
1126 // value of the variable if the property is already there.
1127 LookupResult lookup;
1128 global->Lookup(*name, &lookup);
1129 if (lookup.IsProperty()) {
1130 // Determine if the property is local by comparing the holder
1131 // against the global object. The information will be used to
1132 // avoid throwing re-declaration errors when declaring
1133 // variables or constants that exist in the prototype chain.
1134 bool is_local = (*global == lookup.holder());
1135 // Get the property attributes and determine if the property is
1136 // read-only.
1137 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1138 bool is_read_only = (attributes & READ_ONLY) != 0;
1139 if (lookup.type() == INTERCEPTOR) {
1140 // If the interceptor says the property is there, we
1141 // just return undefined without overwriting the property.
1142 // Otherwise, we continue to setting the property.
1143 if (attributes != ABSENT) {
1144 // Check if the existing property conflicts with regards to const.
1145 if (is_local && (is_read_only || is_const_property)) {
1146 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001147 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148 };
1149 // The property already exists without conflicting: Go to
1150 // the next declaration.
1151 continue;
1152 }
1153 // Fall-through and introduce the absent property by using
1154 // SetProperty.
1155 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001156 // For const properties, we treat a callback with this name
1157 // even in the prototype as a conflicting declaration.
1158 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001159 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001160 }
1161 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001162 if (is_local && (is_read_only || is_const_property)) {
1163 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001164 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165 }
1166 // The property already exists without conflicting: Go to
1167 // the next declaration.
1168 continue;
1169 }
1170 }
1171 } else {
1172 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001173 Handle<SharedFunctionInfo> shared =
1174 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001176 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1177 context,
1178 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179 value = function;
1180 }
1181
1182 LookupResult lookup;
1183 global->LocalLookup(*name, &lookup);
1184
1185 PropertyAttributes attributes = is_const_property
1186 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1187 : base;
1188
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001189 // There's a local property that we need to overwrite because
1190 // we're either declaring a function or there's an interceptor
1191 // that claims the property is absent.
1192 //
1193 // Check for conflicting re-declarations. We cannot have
1194 // conflicting types in case of intercepted properties because
1195 // they are absent.
1196 if (lookup.IsProperty() &&
1197 (lookup.type() != INTERCEPTOR) &&
1198 (lookup.IsReadOnly() || is_const_property)) {
1199 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001200 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001201 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001202
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001203 // Safari does not allow the invocation of callback setters for
1204 // function declarations. To mimic this behavior, we do not allow
1205 // the invocation of setters for function values. This makes a
1206 // difference for global functions with the same names as event
1207 // handlers such as "function onload() {}". Firefox does call the
1208 // onload setter in those case and Safari does not. We follow
1209 // Safari for compatibility.
1210 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001211 // Do not change DONT_DELETE to false from true.
1212 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1213 attributes = static_cast<PropertyAttributes>(
1214 attributes | (lookup.GetAttributes() & DONT_DELETE));
1215 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001216 RETURN_IF_EMPTY_HANDLE(isolate,
1217 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001218 name,
1219 value,
1220 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001221 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001222 RETURN_IF_EMPTY_HANDLE(isolate,
1223 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001224 name,
1225 value,
1226 attributes,
1227 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001228 }
1229 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001230
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001231 ASSERT(!isolate->has_pending_exception());
1232 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001233}
1234
1235
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001236static MaybeObject* Runtime_DeclareContextSlot(RUNTIME_CALLING_CONVENTION) {
1237 RUNTIME_GET_ISOLATE;
1238 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001239 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001240
ager@chromium.org7c537e22008-10-16 08:43:32 +00001241 CONVERT_ARG_CHECKED(Context, context, 0);
1242 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001243 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001244 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001245 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001246 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247
1248 // Declarations are always done in the function context.
1249 context = Handle<Context>(context->fcontext());
1250
1251 int index;
1252 PropertyAttributes attributes;
1253 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001254 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001255 context->Lookup(name, flags, &index, &attributes);
1256
1257 if (attributes != ABSENT) {
1258 // The name was declared before; check for conflicting
1259 // re-declarations: This is similar to the code in parser.cc in
1260 // the AstBuildingParser::Declare function.
1261 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1262 // Functions are not read-only.
1263 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1264 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001265 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266 }
1267
1268 // Initialize it if necessary.
1269 if (*initial_value != NULL) {
1270 if (index >= 0) {
1271 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001272 // the function context or the arguments object.
1273 if (holder->IsContext()) {
1274 ASSERT(holder.is_identical_to(context));
1275 if (((attributes & READ_ONLY) == 0) ||
1276 context->get(index)->IsTheHole()) {
1277 context->set(index, *initial_value);
1278 }
1279 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001280 // The holder is an arguments object.
1281 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001282 Handle<Object> result = SetElement(arguments, index, initial_value,
1283 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001284 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285 }
1286 } else {
1287 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001288 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001289 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001290 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001291 SetProperty(context_ext, name, initial_value,
1292 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001293 }
1294 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001296 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001297 // The property is not in the function context. It needs to be
1298 // "declared" in the function context's extension context, or in the
1299 // global context.
1300 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001301 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001302 // The function context's extension context exists - use it.
1303 context_ext = Handle<JSObject>(context->extension());
1304 } else {
1305 // The function context's extension context does not exists - allocate
1306 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001307 context_ext = isolate->factory()->NewJSObject(
1308 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001309 // And store it in the extension slot.
1310 context->set_extension(*context_ext);
1311 }
1312 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001313
ager@chromium.org7c537e22008-10-16 08:43:32 +00001314 // Declare the property by setting it to the initial value if provided,
1315 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1316 // constant declarations).
1317 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001318 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001319 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001320 // Declaring a const context slot is a conflicting declaration if
1321 // there is a callback with that name in a prototype. It is
1322 // allowed to introduce const variables in
1323 // JSContextExtensionObjects. They are treated specially in
1324 // SetProperty and no setters are invoked for those since they are
1325 // not real JSObjects.
1326 if (initial_value->IsTheHole() &&
1327 !context_ext->IsJSContextExtensionObject()) {
1328 LookupResult lookup;
1329 context_ext->Lookup(*name, &lookup);
1330 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001331 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001332 }
1333 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001334 RETURN_IF_EMPTY_HANDLE(isolate,
1335 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001336 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001337 }
1338
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001339 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001340}
1341
1342
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001343static MaybeObject* Runtime_InitializeVarGlobal(RUNTIME_CALLING_CONVENTION) {
1344 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001346 // args[0] == name
1347 // args[1] == strict_mode
1348 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001349
1350 // Determine if we need to assign to the variable if it already
1351 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001352 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1353 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001354
1355 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001356 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001357 RUNTIME_ASSERT(args[1]->IsSmi());
1358 StrictModeFlag strict_mode =
1359 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1360 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001361
1362 // According to ECMA-262, section 12.2, page 62, the property must
1363 // not be deletable.
1364 PropertyAttributes attributes = DONT_DELETE;
1365
1366 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001367 // there, there is a property with this name in the prototype chain.
1368 // We follow Safari and Firefox behavior and only set the property
1369 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001370 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001371 // Note that objects can have hidden prototypes, so we need to traverse
1372 // the whole chain of hidden prototypes to do a 'local' lookup.
1373 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001374 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001375 while (true) {
1376 real_holder->LocalLookup(*name, &lookup);
1377 if (lookup.IsProperty()) {
1378 // Determine if this is a redeclaration of something read-only.
1379 if (lookup.IsReadOnly()) {
1380 // If we found readonly property on one of hidden prototypes,
1381 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001382 if (real_holder != isolate->context()->global()) break;
1383 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001384 }
1385
1386 // Determine if this is a redeclaration of an intercepted read-only
1387 // property and figure out if the property exists at all.
1388 bool found = true;
1389 PropertyType type = lookup.type();
1390 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001391 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001392 Handle<JSObject> holder(real_holder);
1393 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1394 real_holder = *holder;
1395 if (intercepted == ABSENT) {
1396 // The interceptor claims the property isn't there. We need to
1397 // make sure to introduce it.
1398 found = false;
1399 } else if ((intercepted & READ_ONLY) != 0) {
1400 // The property is present, but read-only. Since we're trying to
1401 // overwrite it with a variable declaration we must throw a
1402 // re-declaration error. However if we found readonly property
1403 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001404 if (real_holder != isolate->context()->global()) break;
1405 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001406 }
1407 }
1408
1409 if (found && !assign) {
1410 // The global property is there and we're not assigning any value
1411 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001412 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001413 }
1414
1415 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001416 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001417 return real_holder->SetProperty(
1418 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001419 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001420
1421 Object* proto = real_holder->GetPrototype();
1422 if (!proto->IsJSObject())
1423 break;
1424
1425 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1426 break;
1427
1428 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001429 }
1430
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001431 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001432 if (assign) {
1433 return global->SetProperty(*name, args[2], attributes, strict_mode);
1434 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001435 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001436}
1437
1438
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001439static MaybeObject* Runtime_InitializeConstGlobal(RUNTIME_CALLING_CONVENTION) {
1440 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001441 // All constants are declared with an initial value. The name
1442 // of the constant is the first argument and the initial value
1443 // is the second.
1444 RUNTIME_ASSERT(args.length() == 2);
1445 CONVERT_ARG_CHECKED(String, name, 0);
1446 Handle<Object> value = args.at<Object>(1);
1447
1448 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001449 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001450
1451 // According to ECMA-262, section 12.2, page 62, the property must
1452 // not be deletable. Since it's a const, it must be READ_ONLY too.
1453 PropertyAttributes attributes =
1454 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1455
1456 // Lookup the property locally in the global object. If it isn't
1457 // there, we add the property and take special precautions to always
1458 // add it as a local property even in case of callbacks in the
1459 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001460 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001461 LookupResult lookup;
1462 global->LocalLookup(*name, &lookup);
1463 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001464 return global->SetLocalPropertyIgnoreAttributes(*name,
1465 *value,
1466 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467 }
1468
1469 // Determine if this is a redeclaration of something not
1470 // read-only. In case the result is hidden behind an interceptor we
1471 // need to ask it for the property attributes.
1472 if (!lookup.IsReadOnly()) {
1473 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001474 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475 }
1476
1477 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1478
1479 // Throw re-declaration error if the intercepted property is present
1480 // but not read-only.
1481 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001482 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001483 }
1484
1485 // Restore global object from context (in case of GC) and continue
1486 // with setting the value because the property is either absent or
1487 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001488 HandleScope handle_scope(isolate);
1489 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001491 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001492 // property through an interceptor and only do it if it's
1493 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001494 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001495 RETURN_IF_EMPTY_HANDLE(isolate,
1496 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001497 name,
1498 value,
1499 attributes,
1500 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501 return *value;
1502 }
1503
1504 // Set the value, but only we're assigning the initial value to a
1505 // constant. For now, we determine this by checking if the
1506 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001507 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001508 PropertyType type = lookup.type();
1509 if (type == FIELD) {
1510 FixedArray* properties = global->properties();
1511 int index = lookup.GetFieldIndex();
1512 if (properties->get(index)->IsTheHole()) {
1513 properties->set(index, *value);
1514 }
1515 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001516 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1517 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001518 }
1519 } else {
1520 // Ignore re-initialization of constants that have already been
1521 // assigned a function value.
1522 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1523 }
1524
1525 // Use the set value as the result of the operation.
1526 return *value;
1527}
1528
1529
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001530static MaybeObject* Runtime_InitializeConstContextSlot(
1531 RUNTIME_CALLING_CONVENTION) {
1532 RUNTIME_GET_ISOLATE;
1533 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 ASSERT(args.length() == 3);
1535
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001536 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001537 ASSERT(!value->IsTheHole());
1538 CONVERT_ARG_CHECKED(Context, context, 1);
1539 Handle<String> name(String::cast(args[2]));
1540
1541 // Initializations are always done in the function context.
1542 context = Handle<Context>(context->fcontext());
1543
1544 int index;
1545 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001546 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001547 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548 context->Lookup(name, flags, &index, &attributes);
1549
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001550 // In most situations, the property introduced by the const
1551 // declaration should be present in the context extension object.
1552 // However, because declaration and initialization are separate, the
1553 // property might have been deleted (if it was introduced by eval)
1554 // before we reach the initialization point.
1555 //
1556 // Example:
1557 //
1558 // function f() { eval("delete x; const x;"); }
1559 //
1560 // In that case, the initialization behaves like a normal assignment
1561 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001563 // Property was found in a context.
1564 if (holder->IsContext()) {
1565 // The holder cannot be the function context. If it is, there
1566 // should have been a const redeclaration error when declaring
1567 // the const property.
1568 ASSERT(!holder.is_identical_to(context));
1569 if ((attributes & READ_ONLY) == 0) {
1570 Handle<Context>::cast(holder)->set(index, *value);
1571 }
1572 } else {
1573 // The holder is an arguments object.
1574 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001575 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001576 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001577 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001578 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001579 }
1580 return *value;
1581 }
1582
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001583 // The property could not be found, we introduce it in the global
1584 // context.
1585 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001586 Handle<JSObject> global = Handle<JSObject>(
1587 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001588 // Strict mode not needed (const disallowed in strict mode).
1589 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001590 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001591 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001592 return *value;
1593 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001595 // The property was present in a context extension object.
1596 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001597
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001598 if (*context_ext == context->extension()) {
1599 // This is the property that was introduced by the const
1600 // declaration. Set it if it hasn't been set before. NOTE: We
1601 // cannot use GetProperty() to get the current value as it
1602 // 'unholes' the value.
1603 LookupResult lookup;
1604 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1605 ASSERT(lookup.IsProperty()); // the property was declared
1606 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1607
1608 PropertyType type = lookup.type();
1609 if (type == FIELD) {
1610 FixedArray* properties = context_ext->properties();
1611 int index = lookup.GetFieldIndex();
1612 if (properties->get(index)->IsTheHole()) {
1613 properties->set(index, *value);
1614 }
1615 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001616 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1617 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001618 }
1619 } else {
1620 // We should not reach here. Any real, named property should be
1621 // either a field or a dictionary slot.
1622 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001623 }
1624 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001625 // The property was found in a different context extension object.
1626 // Set it if it is not a read-only property.
1627 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001628 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001629 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001630 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001631 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001632 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001633 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001634
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635 return *value;
1636}
1637
1638
lrn@chromium.org303ada72010-10-27 09:33:13 +00001639static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001640 RUNTIME_CALLING_CONVENTION) {
1641 RUNTIME_GET_ISOLATE;
1642 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001643 ASSERT(args.length() == 2);
1644 CONVERT_ARG_CHECKED(JSObject, object, 0);
1645 CONVERT_SMI_CHECKED(properties, args[1]);
1646 if (object->HasFastProperties()) {
1647 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1648 }
1649 return *object;
1650}
1651
1652
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001653static MaybeObject* Runtime_RegExpExec(RUNTIME_CALLING_CONVENTION) {
1654 RUNTIME_GET_ISOLATE;
1655 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001656 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001657 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1658 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001659 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001660 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001661 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001662 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001663 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001664 RUNTIME_ASSERT(index >= 0);
1665 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001666 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001667 Handle<Object> result = RegExpImpl::Exec(regexp,
1668 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001669 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001670 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001671 if (result.is_null()) return Failure::Exception();
1672 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001673}
1674
1675
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001676static MaybeObject* Runtime_RegExpConstructResult(RUNTIME_CALLING_CONVENTION) {
1677 RUNTIME_GET_ISOLATE;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001678 ASSERT(args.length() == 3);
1679 CONVERT_SMI_CHECKED(elements_count, args[0]);
1680 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001681 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001682 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001683 Object* new_object;
1684 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001685 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001686 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1687 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001688 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001689 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1690 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001691 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1692 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001693 {
1694 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001695 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001696 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001697 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001698 }
1699 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001700 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001701 array->set_elements(elements);
1702 array->set_length(Smi::FromInt(elements_count));
1703 // Write in-object properties after the length of the array.
1704 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1705 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1706 return array;
1707}
1708
1709
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001710static MaybeObject* Runtime_RegExpInitializeObject(RUNTIME_CALLING_CONVENTION) {
1711 RUNTIME_GET_ISOLATE;
lrn@chromium.org25156de2010-04-06 13:10:27 +00001712 AssertNoAllocation no_alloc;
1713 ASSERT(args.length() == 5);
1714 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1715 CONVERT_CHECKED(String, source, args[1]);
1716
1717 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001718 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001719
1720 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001721 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001722
1723 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001724 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001725
1726 Map* map = regexp->map();
1727 Object* constructor = map->constructor();
1728 if (constructor->IsJSFunction() &&
1729 JSFunction::cast(constructor)->initial_map() == map) {
1730 // If we still have the original map, set in-object properties directly.
1731 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1732 // TODO(lrn): Consider skipping write barrier on booleans as well.
1733 // Both true and false should be in oldspace at all times.
1734 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1735 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1736 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1737 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1738 Smi::FromInt(0),
1739 SKIP_WRITE_BARRIER);
1740 return regexp;
1741 }
1742
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001743 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001744 PropertyAttributes final =
1745 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1746 PropertyAttributes writable =
1747 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001748 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001749 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001750 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001751 source,
1752 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001753 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001754 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001755 global,
1756 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001757 ASSERT(!result->IsFailure());
1758 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001759 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001760 ignoreCase,
1761 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001762 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001764 multiline,
1765 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001766 ASSERT(!result->IsFailure());
1767 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001768 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001769 Smi::FromInt(0),
1770 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001771 ASSERT(!result->IsFailure());
1772 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001773 return regexp;
1774}
1775
1776
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001777static MaybeObject* Runtime_FinishArrayPrototypeSetup(
1778 RUNTIME_CALLING_CONVENTION) {
1779 RUNTIME_GET_ISOLATE;
1780 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001781 ASSERT(args.length() == 1);
1782 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1783 // This is necessary to enable fast checks for absence of elements
1784 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001785 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001786 return Smi::FromInt(0);
1787}
1788
1789
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001790static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1791 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001792 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001793 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001794 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1795 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1796 Handle<JSFunction> optimized =
1797 isolate->factory()->NewFunction(key,
1798 JS_OBJECT_TYPE,
1799 JSObject::kHeaderSize,
1800 code,
1801 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001802 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001803 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001804 return optimized;
1805}
1806
1807
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001808static MaybeObject* Runtime_SpecialArrayFunctions(RUNTIME_CALLING_CONVENTION) {
1809 RUNTIME_GET_ISOLATE;
1810 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001811 ASSERT(args.length() == 1);
1812 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1813
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001814 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1815 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1816 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1817 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1818 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1819 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1820 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001821
1822 return *holder;
1823}
1824
1825
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001826static MaybeObject* Runtime_GetGlobalReceiver(RUNTIME_CALLING_CONVENTION) {
1827 RUNTIME_GET_ISOLATE;
ager@chromium.org357bf652010-04-12 11:30:10 +00001828 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001829 Context* global_context =
1830 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001831 return global_context->global()->global_receiver();
1832}
1833
1834
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001835static MaybeObject* Runtime_MaterializeRegExpLiteral(
1836 RUNTIME_CALLING_CONVENTION) {
1837 RUNTIME_GET_ISOLATE;
1838 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001839 ASSERT(args.length() == 4);
1840 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1841 int index = Smi::cast(args[1])->value();
1842 Handle<String> pattern = args.at<String>(2);
1843 Handle<String> flags = args.at<String>(3);
1844
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001845 // Get the RegExp function from the context in the literals array.
1846 // This is the RegExp function from the context in which the
1847 // function was created. We do not use the RegExp function from the
1848 // current global context because this might be the RegExp function
1849 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001850 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001851 Handle<JSFunction>(
1852 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001853 // Compute the regular expression literal.
1854 bool has_pending_exception;
1855 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001856 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1857 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001858 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001859 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001860 return Failure::Exception();
1861 }
1862 literals->set(index, *regexp);
1863 return *regexp;
1864}
1865
1866
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001867static MaybeObject* Runtime_FunctionGetName(RUNTIME_CALLING_CONVENTION) {
1868 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001869 NoHandleAllocation ha;
1870 ASSERT(args.length() == 1);
1871
1872 CONVERT_CHECKED(JSFunction, f, args[0]);
1873 return f->shared()->name();
1874}
1875
1876
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001877static MaybeObject* Runtime_FunctionSetName(RUNTIME_CALLING_CONVENTION) {
1878 RUNTIME_GET_ISOLATE;
ager@chromium.org236ad962008-09-25 09:45:57 +00001879 NoHandleAllocation ha;
1880 ASSERT(args.length() == 2);
1881
1882 CONVERT_CHECKED(JSFunction, f, args[0]);
1883 CONVERT_CHECKED(String, name, args[1]);
1884 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001885 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001886}
1887
1888
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001889static MaybeObject* Runtime_FunctionRemovePrototype(
1890 RUNTIME_CALLING_CONVENTION) {
1891 RUNTIME_GET_ISOLATE;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001892 NoHandleAllocation ha;
1893 ASSERT(args.length() == 1);
1894
1895 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001896 Object* obj = f->RemovePrototype();
1897 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001898
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001899 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001900}
1901
1902
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001903static MaybeObject* Runtime_FunctionGetScript(RUNTIME_CALLING_CONVENTION) {
1904 RUNTIME_GET_ISOLATE;
1905 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001906 ASSERT(args.length() == 1);
1907
1908 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001909 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1910 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001911
1912 return *GetScriptWrapper(Handle<Script>::cast(script));
1913}
1914
1915
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001916static MaybeObject* Runtime_FunctionGetSourceCode(RUNTIME_CALLING_CONVENTION) {
1917 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001918 NoHandleAllocation ha;
1919 ASSERT(args.length() == 1);
1920
1921 CONVERT_CHECKED(JSFunction, f, args[0]);
1922 return f->shared()->GetSourceCode();
1923}
1924
1925
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001926static MaybeObject* Runtime_FunctionGetScriptSourcePosition(
1927 RUNTIME_CALLING_CONVENTION) {
1928 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001929 NoHandleAllocation ha;
1930 ASSERT(args.length() == 1);
1931
1932 CONVERT_CHECKED(JSFunction, fun, args[0]);
1933 int pos = fun->shared()->start_position();
1934 return Smi::FromInt(pos);
1935}
1936
1937
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001938static MaybeObject* Runtime_FunctionGetPositionForOffset(
1939 RUNTIME_CALLING_CONVENTION) {
1940 RUNTIME_GET_ISOLATE;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001941 ASSERT(args.length() == 2);
1942
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001943 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001944 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1945
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001946 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1947
1948 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001949 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001950}
1951
1952
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001953static MaybeObject* Runtime_FunctionSetInstanceClassName(
1954 RUNTIME_CALLING_CONVENTION) {
1955 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001956 NoHandleAllocation ha;
1957 ASSERT(args.length() == 2);
1958
1959 CONVERT_CHECKED(JSFunction, fun, args[0]);
1960 CONVERT_CHECKED(String, name, args[1]);
1961 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001962 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001963}
1964
1965
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001966static MaybeObject* Runtime_FunctionSetLength(RUNTIME_CALLING_CONVENTION) {
1967 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001968 NoHandleAllocation ha;
1969 ASSERT(args.length() == 2);
1970
1971 CONVERT_CHECKED(JSFunction, fun, args[0]);
1972 CONVERT_CHECKED(Smi, length, args[1]);
1973 fun->shared()->set_length(length->value());
1974 return length;
1975}
1976
1977
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001978static MaybeObject* Runtime_FunctionSetPrototype(RUNTIME_CALLING_CONVENTION) {
1979 RUNTIME_GET_ISOLATE;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001980 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001981 ASSERT(args.length() == 2);
1982
1983 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001984 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001985 Object* obj;
1986 { MaybeObject* maybe_obj =
1987 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1988 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1989 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001990 return args[0]; // return TOS
1991}
1992
1993
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001994static MaybeObject* Runtime_FunctionIsAPIFunction(RUNTIME_CALLING_CONVENTION) {
1995 RUNTIME_GET_ISOLATE;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001996 NoHandleAllocation ha;
1997 ASSERT(args.length() == 1);
1998
1999 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002000 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
2001 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002002}
2003
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002004
2005static MaybeObject* Runtime_FunctionIsBuiltin(RUNTIME_CALLING_CONVENTION) {
2006 RUNTIME_GET_ISOLATE;
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002007 NoHandleAllocation ha;
2008 ASSERT(args.length() == 1);
2009
2010 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002011 return f->IsBuiltin() ? isolate->heap()->true_value() :
2012 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002013}
2014
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002015
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002016static MaybeObject* Runtime_SetCode(RUNTIME_CALLING_CONVENTION) {
2017 RUNTIME_GET_ISOLATE;
2018 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002019 ASSERT(args.length() == 2);
2020
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002021 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002022 Handle<Object> code = args.at<Object>(1);
2023
2024 Handle<Context> context(target->context());
2025
2026 if (!code->IsNull()) {
2027 RUNTIME_ASSERT(code->IsJSFunction());
2028 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002029 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002030
2031 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002032 return Failure::Exception();
2033 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002034 // Since we don't store the source for this we should never
2035 // optimize this.
2036 shared->code()->set_optimizable(false);
2037
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002038 // Set the code, scope info, formal parameter count,
2039 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002040 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002041 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002042 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002043 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002044 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002045 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002046 // Set the source code of the target function to undefined.
2047 // SetCode is only used for built-in constructors like String,
2048 // Array, and Object, and some web code
2049 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002050 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002051 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002052 // Clear the optimization hints related to the compiled code as these are no
2053 // longer valid when the code is overwritten.
2054 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002055 context = Handle<Context>(fun->context());
2056
2057 // Make sure we get a fresh copy of the literal vector to avoid
2058 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002059 int number_of_literals = fun->NumberOfLiterals();
2060 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002061 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002062 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002063 // Insert the object, regexp and array functions in the literals
2064 // array prefix. These are the functions that will be used when
2065 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002066 literals->set(JSFunction::kLiteralGlobalContextIndex,
2067 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002068 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002069 // It's okay to skip the write barrier here because the literals
2070 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002071 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002072 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002073 }
2074
2075 target->set_context(*context);
2076 return *target;
2077}
2078
2079
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002080static MaybeObject* Runtime_SetExpectedNumberOfProperties(
2081 RUNTIME_CALLING_CONVENTION) {
2082 RUNTIME_GET_ISOLATE;
2083 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002084 ASSERT(args.length() == 2);
2085 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2086 CONVERT_SMI_CHECKED(num, args[1]);
2087 RUNTIME_ASSERT(num >= 0);
2088 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002089 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002090}
2091
2092
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002093MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2094 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002095 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002096 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002097 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002098 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002099 }
2100 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002101 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002102}
2103
2104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002105static MaybeObject* Runtime_StringCharCodeAt(RUNTIME_CALLING_CONVENTION) {
2106 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002107 NoHandleAllocation ha;
2108 ASSERT(args.length() == 2);
2109
2110 CONVERT_CHECKED(String, subject, args[0]);
2111 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002112 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002113
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002114 uint32_t i = 0;
2115 if (index->IsSmi()) {
2116 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002117 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002118 i = value;
2119 } else {
2120 ASSERT(index->IsHeapNumber());
2121 double value = HeapNumber::cast(index)->value();
2122 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002123 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002124
2125 // Flatten the string. If someone wants to get a char at an index
2126 // in a cons string, it is likely that more indices will be
2127 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002128 Object* flat;
2129 { MaybeObject* maybe_flat = subject->TryFlatten();
2130 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2131 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002132 subject = String::cast(flat);
2133
2134 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002135 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002136 }
2137
2138 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002139}
2140
2141
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002142static MaybeObject* Runtime_CharFromCode(RUNTIME_CALLING_CONVENTION) {
2143 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002144 NoHandleAllocation ha;
2145 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002146 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002147}
2148
lrn@chromium.org25156de2010-04-06 13:10:27 +00002149
2150class FixedArrayBuilder {
2151 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002152 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2153 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002154 length_(0) {
2155 // Require a non-zero initial size. Ensures that doubling the size to
2156 // extend the array will work.
2157 ASSERT(initial_capacity > 0);
2158 }
2159
2160 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2161 : array_(backing_store),
2162 length_(0) {
2163 // Require a non-zero initial size. Ensures that doubling the size to
2164 // extend the array will work.
2165 ASSERT(backing_store->length() > 0);
2166 }
2167
2168 bool HasCapacity(int elements) {
2169 int length = array_->length();
2170 int required_length = length_ + elements;
2171 return (length >= required_length);
2172 }
2173
2174 void EnsureCapacity(int elements) {
2175 int length = array_->length();
2176 int required_length = length_ + elements;
2177 if (length < required_length) {
2178 int new_length = length;
2179 do {
2180 new_length *= 2;
2181 } while (new_length < required_length);
2182 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002183 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002184 array_->CopyTo(0, *extended_array, 0, length_);
2185 array_ = extended_array;
2186 }
2187 }
2188
2189 void Add(Object* value) {
2190 ASSERT(length_ < capacity());
2191 array_->set(length_, value);
2192 length_++;
2193 }
2194
2195 void Add(Smi* value) {
2196 ASSERT(length_ < capacity());
2197 array_->set(length_, value);
2198 length_++;
2199 }
2200
2201 Handle<FixedArray> array() {
2202 return array_;
2203 }
2204
2205 int length() {
2206 return length_;
2207 }
2208
2209 int capacity() {
2210 return array_->length();
2211 }
2212
2213 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002214 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002215 result_array->set_length(Smi::FromInt(length_));
2216 return result_array;
2217 }
2218
2219 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2220 target_array->set_elements(*array_);
2221 target_array->set_length(Smi::FromInt(length_));
2222 return target_array;
2223 }
2224
2225 private:
2226 Handle<FixedArray> array_;
2227 int length_;
2228};
2229
2230
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002231// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002232const int kStringBuilderConcatHelperLengthBits = 11;
2233const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002234
2235template <typename schar>
2236static inline void StringBuilderConcatHelper(String*,
2237 schar*,
2238 FixedArray*,
2239 int);
2240
lrn@chromium.org25156de2010-04-06 13:10:27 +00002241typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2242 StringBuilderSubstringLength;
2243typedef BitField<int,
2244 kStringBuilderConcatHelperLengthBits,
2245 kStringBuilderConcatHelperPositionBits>
2246 StringBuilderSubstringPosition;
2247
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002248
2249class ReplacementStringBuilder {
2250 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002251 ReplacementStringBuilder(Heap* heap,
2252 Handle<String> subject,
2253 int estimated_part_count)
2254 : heap_(heap),
2255 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002256 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002257 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002258 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002259 // Require a non-zero initial size. Ensures that doubling the size to
2260 // extend the array will work.
2261 ASSERT(estimated_part_count > 0);
2262 }
2263
lrn@chromium.org25156de2010-04-06 13:10:27 +00002264 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2265 int from,
2266 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002267 ASSERT(from >= 0);
2268 int length = to - from;
2269 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002270 if (StringBuilderSubstringLength::is_valid(length) &&
2271 StringBuilderSubstringPosition::is_valid(from)) {
2272 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2273 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002274 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002275 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002276 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002277 builder->Add(Smi::FromInt(-length));
2278 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002279 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002280 }
2281
2282
2283 void EnsureCapacity(int elements) {
2284 array_builder_.EnsureCapacity(elements);
2285 }
2286
2287
2288 void AddSubjectSlice(int from, int to) {
2289 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002290 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002291 }
2292
2293
2294 void AddString(Handle<String> string) {
2295 int length = string->length();
2296 ASSERT(length > 0);
2297 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002298 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002299 is_ascii_ = false;
2300 }
2301 IncrementCharacterCount(length);
2302 }
2303
2304
2305 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002306 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002307 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002308 }
2309
2310 Handle<String> joined_string;
2311 if (is_ascii_) {
2312 joined_string = NewRawAsciiString(character_count_);
2313 AssertNoAllocation no_alloc;
2314 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2315 char* char_buffer = seq->GetChars();
2316 StringBuilderConcatHelper(*subject_,
2317 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002318 *array_builder_.array(),
2319 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002320 } else {
2321 // Non-ASCII.
2322 joined_string = NewRawTwoByteString(character_count_);
2323 AssertNoAllocation no_alloc;
2324 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2325 uc16* char_buffer = seq->GetChars();
2326 StringBuilderConcatHelper(*subject_,
2327 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002328 *array_builder_.array(),
2329 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002330 }
2331 return joined_string;
2332 }
2333
2334
2335 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002336 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002337 V8::FatalProcessOutOfMemory("String.replace result too large.");
2338 }
2339 character_count_ += by;
2340 }
2341
lrn@chromium.org25156de2010-04-06 13:10:27 +00002342 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002343 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002344 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002345
lrn@chromium.org25156de2010-04-06 13:10:27 +00002346 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002347 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002348 CALL_HEAP_FUNCTION(heap_->isolate(),
2349 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002350 }
2351
2352
2353 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002354 CALL_HEAP_FUNCTION(heap_->isolate(),
2355 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002356 }
2357
2358
2359 void AddElement(Object* element) {
2360 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002361 ASSERT(array_builder_.capacity() > array_builder_.length());
2362 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002363 }
2364
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002365 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002366 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002367 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002368 int character_count_;
2369 bool is_ascii_;
2370};
2371
2372
2373class CompiledReplacement {
2374 public:
2375 CompiledReplacement()
2376 : parts_(1), replacement_substrings_(0) {}
2377
2378 void Compile(Handle<String> replacement,
2379 int capture_count,
2380 int subject_length);
2381
2382 void Apply(ReplacementStringBuilder* builder,
2383 int match_from,
2384 int match_to,
2385 Handle<JSArray> last_match_info);
2386
2387 // Number of distinct parts of the replacement pattern.
2388 int parts() {
2389 return parts_.length();
2390 }
2391 private:
2392 enum PartType {
2393 SUBJECT_PREFIX = 1,
2394 SUBJECT_SUFFIX,
2395 SUBJECT_CAPTURE,
2396 REPLACEMENT_SUBSTRING,
2397 REPLACEMENT_STRING,
2398
2399 NUMBER_OF_PART_TYPES
2400 };
2401
2402 struct ReplacementPart {
2403 static inline ReplacementPart SubjectMatch() {
2404 return ReplacementPart(SUBJECT_CAPTURE, 0);
2405 }
2406 static inline ReplacementPart SubjectCapture(int capture_index) {
2407 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2408 }
2409 static inline ReplacementPart SubjectPrefix() {
2410 return ReplacementPart(SUBJECT_PREFIX, 0);
2411 }
2412 static inline ReplacementPart SubjectSuffix(int subject_length) {
2413 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2414 }
2415 static inline ReplacementPart ReplacementString() {
2416 return ReplacementPart(REPLACEMENT_STRING, 0);
2417 }
2418 static inline ReplacementPart ReplacementSubString(int from, int to) {
2419 ASSERT(from >= 0);
2420 ASSERT(to > from);
2421 return ReplacementPart(-from, to);
2422 }
2423
2424 // If tag <= 0 then it is the negation of a start index of a substring of
2425 // the replacement pattern, otherwise it's a value from PartType.
2426 ReplacementPart(int tag, int data)
2427 : tag(tag), data(data) {
2428 // Must be non-positive or a PartType value.
2429 ASSERT(tag < NUMBER_OF_PART_TYPES);
2430 }
2431 // Either a value of PartType or a non-positive number that is
2432 // the negation of an index into the replacement string.
2433 int tag;
2434 // The data value's interpretation depends on the value of tag:
2435 // tag == SUBJECT_PREFIX ||
2436 // tag == SUBJECT_SUFFIX: data is unused.
2437 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2438 // tag == REPLACEMENT_SUBSTRING ||
2439 // tag == REPLACEMENT_STRING: data is index into array of substrings
2440 // of the replacement string.
2441 // tag <= 0: Temporary representation of the substring of the replacement
2442 // string ranging over -tag .. data.
2443 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2444 // substring objects.
2445 int data;
2446 };
2447
2448 template<typename Char>
2449 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2450 Vector<Char> characters,
2451 int capture_count,
2452 int subject_length) {
2453 int length = characters.length();
2454 int last = 0;
2455 for (int i = 0; i < length; i++) {
2456 Char c = characters[i];
2457 if (c == '$') {
2458 int next_index = i + 1;
2459 if (next_index == length) { // No next character!
2460 break;
2461 }
2462 Char c2 = characters[next_index];
2463 switch (c2) {
2464 case '$':
2465 if (i > last) {
2466 // There is a substring before. Include the first "$".
2467 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2468 last = next_index + 1; // Continue after the second "$".
2469 } else {
2470 // Let the next substring start with the second "$".
2471 last = next_index;
2472 }
2473 i = next_index;
2474 break;
2475 case '`':
2476 if (i > last) {
2477 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2478 }
2479 parts->Add(ReplacementPart::SubjectPrefix());
2480 i = next_index;
2481 last = i + 1;
2482 break;
2483 case '\'':
2484 if (i > last) {
2485 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2486 }
2487 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2488 i = next_index;
2489 last = i + 1;
2490 break;
2491 case '&':
2492 if (i > last) {
2493 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2494 }
2495 parts->Add(ReplacementPart::SubjectMatch());
2496 i = next_index;
2497 last = i + 1;
2498 break;
2499 case '0':
2500 case '1':
2501 case '2':
2502 case '3':
2503 case '4':
2504 case '5':
2505 case '6':
2506 case '7':
2507 case '8':
2508 case '9': {
2509 int capture_ref = c2 - '0';
2510 if (capture_ref > capture_count) {
2511 i = next_index;
2512 continue;
2513 }
2514 int second_digit_index = next_index + 1;
2515 if (second_digit_index < length) {
2516 // Peek ahead to see if we have two digits.
2517 Char c3 = characters[second_digit_index];
2518 if ('0' <= c3 && c3 <= '9') { // Double digits.
2519 int double_digit_ref = capture_ref * 10 + c3 - '0';
2520 if (double_digit_ref <= capture_count) {
2521 next_index = second_digit_index;
2522 capture_ref = double_digit_ref;
2523 }
2524 }
2525 }
2526 if (capture_ref > 0) {
2527 if (i > last) {
2528 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2529 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002530 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002531 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2532 last = next_index + 1;
2533 }
2534 i = next_index;
2535 break;
2536 }
2537 default:
2538 i = next_index;
2539 break;
2540 }
2541 }
2542 }
2543 if (length > last) {
2544 if (last == 0) {
2545 parts->Add(ReplacementPart::ReplacementString());
2546 } else {
2547 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2548 }
2549 }
2550 }
2551
2552 ZoneList<ReplacementPart> parts_;
2553 ZoneList<Handle<String> > replacement_substrings_;
2554};
2555
2556
2557void CompiledReplacement::Compile(Handle<String> replacement,
2558 int capture_count,
2559 int subject_length) {
2560 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002561 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002562 AssertNoAllocation no_alloc;
2563 ParseReplacementPattern(&parts_,
2564 replacement->ToAsciiVector(),
2565 capture_count,
2566 subject_length);
2567 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002568 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002569 AssertNoAllocation no_alloc;
2570
2571 ParseReplacementPattern(&parts_,
2572 replacement->ToUC16Vector(),
2573 capture_count,
2574 subject_length);
2575 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002576 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002577 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002578 int substring_index = 0;
2579 for (int i = 0, n = parts_.length(); i < n; i++) {
2580 int tag = parts_[i].tag;
2581 if (tag <= 0) { // A replacement string slice.
2582 int from = -tag;
2583 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002584 replacement_substrings_.Add(
2585 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002586 parts_[i].tag = REPLACEMENT_SUBSTRING;
2587 parts_[i].data = substring_index;
2588 substring_index++;
2589 } else if (tag == REPLACEMENT_STRING) {
2590 replacement_substrings_.Add(replacement);
2591 parts_[i].data = substring_index;
2592 substring_index++;
2593 }
2594 }
2595}
2596
2597
2598void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2599 int match_from,
2600 int match_to,
2601 Handle<JSArray> last_match_info) {
2602 for (int i = 0, n = parts_.length(); i < n; i++) {
2603 ReplacementPart part = parts_[i];
2604 switch (part.tag) {
2605 case SUBJECT_PREFIX:
2606 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2607 break;
2608 case SUBJECT_SUFFIX: {
2609 int subject_length = part.data;
2610 if (match_to < subject_length) {
2611 builder->AddSubjectSlice(match_to, subject_length);
2612 }
2613 break;
2614 }
2615 case SUBJECT_CAPTURE: {
2616 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002617 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002618 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2619 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2620 if (from >= 0 && to > from) {
2621 builder->AddSubjectSlice(from, to);
2622 }
2623 break;
2624 }
2625 case REPLACEMENT_SUBSTRING:
2626 case REPLACEMENT_STRING:
2627 builder->AddString(replacement_substrings_[part.data]);
2628 break;
2629 default:
2630 UNREACHABLE();
2631 }
2632 }
2633}
2634
2635
2636
lrn@chromium.org303ada72010-10-27 09:33:13 +00002637MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002638 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002639 String* subject,
2640 JSRegExp* regexp,
2641 String* replacement,
2642 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002643 ASSERT(subject->IsFlat());
2644 ASSERT(replacement->IsFlat());
2645
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002646 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002647
2648 int length = subject->length();
2649 Handle<String> subject_handle(subject);
2650 Handle<JSRegExp> regexp_handle(regexp);
2651 Handle<String> replacement_handle(replacement);
2652 Handle<JSArray> last_match_info_handle(last_match_info);
2653 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2654 subject_handle,
2655 0,
2656 last_match_info_handle);
2657 if (match.is_null()) {
2658 return Failure::Exception();
2659 }
2660 if (match->IsNull()) {
2661 return *subject_handle;
2662 }
2663
2664 int capture_count = regexp_handle->CaptureCount();
2665
2666 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002667 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002668 CompiledReplacement compiled_replacement;
2669 compiled_replacement.Compile(replacement_handle,
2670 capture_count,
2671 length);
2672
2673 bool is_global = regexp_handle->GetFlags().is_global();
2674
2675 // Guessing the number of parts that the final result string is built
2676 // from. Global regexps can match any number of times, so we guess
2677 // conservatively.
2678 int expected_parts =
2679 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002680 ReplacementStringBuilder builder(isolate->heap(),
2681 subject_handle,
2682 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002683
2684 // Index of end of last match.
2685 int prev = 0;
2686
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002687 // Number of parts added by compiled replacement plus preceeding
2688 // string and possibly suffix after last match. It is possible for
2689 // all components to use two elements when encoded as two smis.
2690 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002691 bool matched = true;
2692 do {
2693 ASSERT(last_match_info_handle->HasFastElements());
2694 // Increase the capacity of the builder before entering local handle-scope,
2695 // so its internal buffer can safely allocate a new handle if it grows.
2696 builder.EnsureCapacity(parts_added_per_loop);
2697
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002698 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002699 int start, end;
2700 {
2701 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002702 FixedArray* match_info_array =
2703 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002704
2705 ASSERT_EQ(capture_count * 2 + 2,
2706 RegExpImpl::GetLastCaptureCount(match_info_array));
2707 start = RegExpImpl::GetCapture(match_info_array, 0);
2708 end = RegExpImpl::GetCapture(match_info_array, 1);
2709 }
2710
2711 if (prev < start) {
2712 builder.AddSubjectSlice(prev, start);
2713 }
2714 compiled_replacement.Apply(&builder,
2715 start,
2716 end,
2717 last_match_info_handle);
2718 prev = end;
2719
2720 // Only continue checking for global regexps.
2721 if (!is_global) break;
2722
2723 // Continue from where the match ended, unless it was an empty match.
2724 int next = end;
2725 if (start == end) {
2726 next = end + 1;
2727 if (next > length) break;
2728 }
2729
2730 match = RegExpImpl::Exec(regexp_handle,
2731 subject_handle,
2732 next,
2733 last_match_info_handle);
2734 if (match.is_null()) {
2735 return Failure::Exception();
2736 }
2737 matched = !match->IsNull();
2738 } while (matched);
2739
2740 if (prev < length) {
2741 builder.AddSubjectSlice(prev, length);
2742 }
2743
2744 return *(builder.ToString());
2745}
2746
2747
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002748template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002749MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002750 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002751 String* subject,
2752 JSRegExp* regexp,
2753 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002754 ASSERT(subject->IsFlat());
2755
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002756 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002757
2758 Handle<String> subject_handle(subject);
2759 Handle<JSRegExp> regexp_handle(regexp);
2760 Handle<JSArray> last_match_info_handle(last_match_info);
2761 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2762 subject_handle,
2763 0,
2764 last_match_info_handle);
2765 if (match.is_null()) return Failure::Exception();
2766 if (match->IsNull()) return *subject_handle;
2767
2768 ASSERT(last_match_info_handle->HasFastElements());
2769
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002770 int start, end;
2771 {
2772 AssertNoAllocation match_info_array_is_not_in_a_handle;
2773 FixedArray* match_info_array =
2774 FixedArray::cast(last_match_info_handle->elements());
2775
2776 start = RegExpImpl::GetCapture(match_info_array, 0);
2777 end = RegExpImpl::GetCapture(match_info_array, 1);
2778 }
2779
2780 int length = subject->length();
2781 int new_length = length - (end - start);
2782 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002783 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002784 }
2785 Handle<ResultSeqString> answer;
2786 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002787 answer = Handle<ResultSeqString>::cast(
2788 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002789 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002790 answer = Handle<ResultSeqString>::cast(
2791 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002792 }
2793
2794 // If the regexp isn't global, only match once.
2795 if (!regexp_handle->GetFlags().is_global()) {
2796 if (start > 0) {
2797 String::WriteToFlat(*subject_handle,
2798 answer->GetChars(),
2799 0,
2800 start);
2801 }
2802 if (end < length) {
2803 String::WriteToFlat(*subject_handle,
2804 answer->GetChars() + start,
2805 end,
2806 length);
2807 }
2808 return *answer;
2809 }
2810
2811 int prev = 0; // Index of end of last match.
2812 int next = 0; // Start of next search (prev unless last match was empty).
2813 int position = 0;
2814
2815 do {
2816 if (prev < start) {
2817 // Add substring subject[prev;start] to answer string.
2818 String::WriteToFlat(*subject_handle,
2819 answer->GetChars() + position,
2820 prev,
2821 start);
2822 position += start - prev;
2823 }
2824 prev = end;
2825 next = end;
2826 // Continue from where the match ended, unless it was an empty match.
2827 if (start == end) {
2828 next++;
2829 if (next > length) break;
2830 }
2831 match = RegExpImpl::Exec(regexp_handle,
2832 subject_handle,
2833 next,
2834 last_match_info_handle);
2835 if (match.is_null()) return Failure::Exception();
2836 if (match->IsNull()) break;
2837
2838 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002839 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002840 {
2841 AssertNoAllocation match_info_array_is_not_in_a_handle;
2842 FixedArray* match_info_array =
2843 FixedArray::cast(last_match_info_handle->elements());
2844 start = RegExpImpl::GetCapture(match_info_array, 0);
2845 end = RegExpImpl::GetCapture(match_info_array, 1);
2846 }
2847 } while (true);
2848
2849 if (prev < length) {
2850 // Add substring subject[prev;length] to answer string.
2851 String::WriteToFlat(*subject_handle,
2852 answer->GetChars() + position,
2853 prev,
2854 length);
2855 position += length - prev;
2856 }
2857
2858 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002859 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002860 }
2861
2862 // Shorten string and fill
2863 int string_size = ResultSeqString::SizeFor(position);
2864 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2865 int delta = allocated_string_size - string_size;
2866
2867 answer->set_length(position);
2868 if (delta == 0) return *answer;
2869
2870 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002871 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002872
2873 return *answer;
2874}
2875
2876
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002877static MaybeObject* Runtime_StringReplaceRegExpWithString(
2878 RUNTIME_CALLING_CONVENTION) {
2879 RUNTIME_GET_ISOLATE;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002880 ASSERT(args.length() == 4);
2881
2882 CONVERT_CHECKED(String, subject, args[0]);
2883 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002884 Object* flat_subject;
2885 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2886 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2887 return maybe_flat_subject;
2888 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002889 }
2890 subject = String::cast(flat_subject);
2891 }
2892
2893 CONVERT_CHECKED(String, replacement, args[2]);
2894 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002895 Object* flat_replacement;
2896 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2897 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2898 return maybe_flat_replacement;
2899 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002900 }
2901 replacement = String::cast(flat_replacement);
2902 }
2903
2904 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2905 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2906
2907 ASSERT(last_match_info->HasFastElements());
2908
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002909 if (replacement->length() == 0) {
2910 if (subject->HasOnlyAsciiChars()) {
2911 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002912 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002913 } else {
2914 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002915 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002916 }
2917 }
2918
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002919 return StringReplaceRegExpWithString(isolate,
2920 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002921 regexp,
2922 replacement,
2923 last_match_info);
2924}
2925
2926
ager@chromium.org7c537e22008-10-16 08:43:32 +00002927// Perform string match of pattern on subject, starting at start index.
2928// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002929// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002930int Runtime::StringMatch(Isolate* isolate,
2931 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002932 Handle<String> pat,
2933 int start_index) {
2934 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002935 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002936
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002937 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002938 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002939
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002940 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002941 if (start_index + pattern_length > subject_length) return -1;
2942
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002943 if (!sub->IsFlat()) FlattenString(sub);
2944 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002945
ager@chromium.org7c537e22008-10-16 08:43:32 +00002946 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002947 // Extract flattened substrings of cons strings before determining asciiness.
2948 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002949 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002950 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002951 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002952
ager@chromium.org7c537e22008-10-16 08:43:32 +00002953 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002954 if (seq_pat->IsAsciiRepresentation()) {
2955 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2956 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002957 return SearchString(isolate,
2958 seq_sub->ToAsciiVector(),
2959 pat_vector,
2960 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002961 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002962 return SearchString(isolate,
2963 seq_sub->ToUC16Vector(),
2964 pat_vector,
2965 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002966 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002967 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2968 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002969 return SearchString(isolate,
2970 seq_sub->ToAsciiVector(),
2971 pat_vector,
2972 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002973 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002974 return SearchString(isolate,
2975 seq_sub->ToUC16Vector(),
2976 pat_vector,
2977 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002978}
2979
2980
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002981static MaybeObject* Runtime_StringIndexOf(RUNTIME_CALLING_CONVENTION) {
2982 RUNTIME_GET_ISOLATE;
2983 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002984 ASSERT(args.length() == 3);
2985
ager@chromium.org7c537e22008-10-16 08:43:32 +00002986 CONVERT_ARG_CHECKED(String, sub, 0);
2987 CONVERT_ARG_CHECKED(String, pat, 1);
2988
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002989 Object* index = args[2];
2990 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002991 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002992
ager@chromium.org870a0b62008-11-04 11:43:05 +00002993 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002994 int position =
2995 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002996 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002997}
2998
2999
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003000template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003001static int StringMatchBackwards(Vector<const schar> subject,
3002 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003003 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003004 int pattern_length = pattern.length();
3005 ASSERT(pattern_length >= 1);
3006 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003007
3008 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003009 for (int i = 0; i < pattern_length; i++) {
3010 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003011 if (c > String::kMaxAsciiCharCode) {
3012 return -1;
3013 }
3014 }
3015 }
3016
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003017 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003018 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003019 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003020 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003021 while (j < pattern_length) {
3022 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003023 break;
3024 }
3025 j++;
3026 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003027 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003028 return i;
3029 }
3030 }
3031 return -1;
3032}
3033
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003034static MaybeObject* Runtime_StringLastIndexOf(RUNTIME_CALLING_CONVENTION) {
3035 RUNTIME_GET_ISOLATE;
3036 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003037 ASSERT(args.length() == 3);
3038
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003039 CONVERT_ARG_CHECKED(String, sub, 0);
3040 CONVERT_ARG_CHECKED(String, pat, 1);
3041
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003042 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003043 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003044 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003045
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003046 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003047 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003048
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003049 if (start_index + pat_length > sub_length) {
3050 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003051 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003052
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003053 if (pat_length == 0) {
3054 return Smi::FromInt(start_index);
3055 }
3056
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003057 if (!sub->IsFlat()) FlattenString(sub);
3058 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003059
3060 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3061
3062 int position = -1;
3063
3064 if (pat->IsAsciiRepresentation()) {
3065 Vector<const char> pat_vector = pat->ToAsciiVector();
3066 if (sub->IsAsciiRepresentation()) {
3067 position = StringMatchBackwards(sub->ToAsciiVector(),
3068 pat_vector,
3069 start_index);
3070 } else {
3071 position = StringMatchBackwards(sub->ToUC16Vector(),
3072 pat_vector,
3073 start_index);
3074 }
3075 } else {
3076 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3077 if (sub->IsAsciiRepresentation()) {
3078 position = StringMatchBackwards(sub->ToAsciiVector(),
3079 pat_vector,
3080 start_index);
3081 } else {
3082 position = StringMatchBackwards(sub->ToUC16Vector(),
3083 pat_vector,
3084 start_index);
3085 }
3086 }
3087
3088 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003089}
3090
3091
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003092static MaybeObject* Runtime_StringLocaleCompare(RUNTIME_CALLING_CONVENTION) {
3093 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003094 NoHandleAllocation ha;
3095 ASSERT(args.length() == 2);
3096
3097 CONVERT_CHECKED(String, str1, args[0]);
3098 CONVERT_CHECKED(String, str2, args[1]);
3099
3100 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003101 int str1_length = str1->length();
3102 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003103
3104 // Decide trivial cases without flattening.
3105 if (str1_length == 0) {
3106 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3107 return Smi::FromInt(-str2_length);
3108 } else {
3109 if (str2_length == 0) return Smi::FromInt(str1_length);
3110 }
3111
3112 int end = str1_length < str2_length ? str1_length : str2_length;
3113
3114 // No need to flatten if we are going to find the answer on the first
3115 // character. At this point we know there is at least one character
3116 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003117 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003118 if (d != 0) return Smi::FromInt(d);
3119
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003120 str1->TryFlatten();
3121 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003122
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003123 StringInputBuffer& buf1 =
3124 *isolate->runtime_state()->string_locale_compare_buf1();
3125 StringInputBuffer& buf2 =
3126 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003127
3128 buf1.Reset(str1);
3129 buf2.Reset(str2);
3130
3131 for (int i = 0; i < end; i++) {
3132 uint16_t char1 = buf1.GetNext();
3133 uint16_t char2 = buf2.GetNext();
3134 if (char1 != char2) return Smi::FromInt(char1 - char2);
3135 }
3136
3137 return Smi::FromInt(str1_length - str2_length);
3138}
3139
3140
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003141static MaybeObject* Runtime_SubString(RUNTIME_CALLING_CONVENTION) {
3142 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003143 NoHandleAllocation ha;
3144 ASSERT(args.length() == 3);
3145
3146 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003147 Object* from = args[1];
3148 Object* to = args[2];
3149 int start, end;
3150 // We have a fast integer-only case here to avoid a conversion to double in
3151 // the common case where from and to are Smis.
3152 if (from->IsSmi() && to->IsSmi()) {
3153 start = Smi::cast(from)->value();
3154 end = Smi::cast(to)->value();
3155 } else {
3156 CONVERT_DOUBLE_CHECKED(from_number, from);
3157 CONVERT_DOUBLE_CHECKED(to_number, to);
3158 start = FastD2I(from_number);
3159 end = FastD2I(to_number);
3160 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003161 RUNTIME_ASSERT(end >= start);
3162 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003163 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003164 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003165 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003166}
3167
3168
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003169static MaybeObject* Runtime_StringMatch(RUNTIME_CALLING_CONVENTION) {
3170 RUNTIME_GET_ISOLATE;
ager@chromium.org41826e72009-03-30 13:30:57 +00003171 ASSERT_EQ(3, args.length());
3172
3173 CONVERT_ARG_CHECKED(String, subject, 0);
3174 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3175 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3176 HandleScope handles;
3177
3178 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3179
3180 if (match.is_null()) {
3181 return Failure::Exception();
3182 }
3183 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003184 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003185 }
3186 int length = subject->length();
3187
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003188 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003189 ZoneList<int> offsets(8);
3190 do {
3191 int start;
3192 int end;
3193 {
3194 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003195 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003196 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3197 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3198 }
3199 offsets.Add(start);
3200 offsets.Add(end);
3201 int index = start < end ? end : end + 1;
3202 if (index > length) break;
3203 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3204 if (match.is_null()) {
3205 return Failure::Exception();
3206 }
3207 } while (!match->IsNull());
3208 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003209 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003210 for (int i = 0; i < matches ; i++) {
3211 int from = offsets.at(i * 2);
3212 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003213 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003214 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003215 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003216 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003217 result->set_length(Smi::FromInt(matches));
3218 return *result;
3219}
3220
3221
lrn@chromium.org25156de2010-04-06 13:10:27 +00003222// Two smis before and after the match, for very long strings.
3223const int kMaxBuilderEntriesPerRegExpMatch = 5;
3224
3225
3226static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3227 Handle<JSArray> last_match_info,
3228 int match_start,
3229 int match_end) {
3230 // Fill last_match_info with a single capture.
3231 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3232 AssertNoAllocation no_gc;
3233 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3234 RegExpImpl::SetLastCaptureCount(elements, 2);
3235 RegExpImpl::SetLastInput(elements, *subject);
3236 RegExpImpl::SetLastSubject(elements, *subject);
3237 RegExpImpl::SetCapture(elements, 0, match_start);
3238 RegExpImpl::SetCapture(elements, 1, match_end);
3239}
3240
3241
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003242template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003243static bool SearchStringMultiple(Isolate* isolate,
3244 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003245 Vector<const PatternChar> pattern,
3246 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003247 FixedArrayBuilder* builder,
3248 int* match_pos) {
3249 int pos = *match_pos;
3250 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003251 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003252 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003253 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003254 while (pos <= max_search_start) {
3255 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3256 *match_pos = pos;
3257 return false;
3258 }
3259 // Position of end of previous match.
3260 int match_end = pos + pattern_length;
3261 int new_pos = search.Search(subject, match_end);
3262 if (new_pos >= 0) {
3263 // A match.
3264 if (new_pos > match_end) {
3265 ReplacementStringBuilder::AddSubjectSlice(builder,
3266 match_end,
3267 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003268 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003269 pos = new_pos;
3270 builder->Add(pattern_string);
3271 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003272 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003273 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003274 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003275
lrn@chromium.org25156de2010-04-06 13:10:27 +00003276 if (pos < max_search_start) {
3277 ReplacementStringBuilder::AddSubjectSlice(builder,
3278 pos + pattern_length,
3279 subject_length);
3280 }
3281 *match_pos = pos;
3282 return true;
3283}
3284
3285
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003286static bool SearchStringMultiple(Isolate* isolate,
3287 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003288 Handle<String> pattern,
3289 Handle<JSArray> last_match_info,
3290 FixedArrayBuilder* builder) {
3291 ASSERT(subject->IsFlat());
3292 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003293
3294 // Treating as if a previous match was before first character.
3295 int match_pos = -pattern->length();
3296
3297 for (;;) { // Break when search complete.
3298 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3299 AssertNoAllocation no_gc;
3300 if (subject->IsAsciiRepresentation()) {
3301 Vector<const char> subject_vector = subject->ToAsciiVector();
3302 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003303 if (SearchStringMultiple(isolate,
3304 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003305 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003306 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003307 builder,
3308 &match_pos)) break;
3309 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003310 if (SearchStringMultiple(isolate,
3311 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003312 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003313 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003314 builder,
3315 &match_pos)) break;
3316 }
3317 } else {
3318 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3319 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003320 if (SearchStringMultiple(isolate,
3321 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003322 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003323 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003324 builder,
3325 &match_pos)) break;
3326 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003327 if (SearchStringMultiple(isolate,
3328 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003329 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003330 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003331 builder,
3332 &match_pos)) break;
3333 }
3334 }
3335 }
3336
3337 if (match_pos >= 0) {
3338 SetLastMatchInfoNoCaptures(subject,
3339 last_match_info,
3340 match_pos,
3341 match_pos + pattern->length());
3342 return true;
3343 }
3344 return false; // No matches at all.
3345}
3346
3347
3348static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003349 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003350 Handle<String> subject,
3351 Handle<JSRegExp> regexp,
3352 Handle<JSArray> last_match_array,
3353 FixedArrayBuilder* builder) {
3354 ASSERT(subject->IsFlat());
3355 int match_start = -1;
3356 int match_end = 0;
3357 int pos = 0;
3358 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3359 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3360
3361 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003362 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003363 int subject_length = subject->length();
3364
3365 for (;;) { // Break on failure, return on exception.
3366 RegExpImpl::IrregexpResult result =
3367 RegExpImpl::IrregexpExecOnce(regexp,
3368 subject,
3369 pos,
3370 register_vector);
3371 if (result == RegExpImpl::RE_SUCCESS) {
3372 match_start = register_vector[0];
3373 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3374 if (match_end < match_start) {
3375 ReplacementStringBuilder::AddSubjectSlice(builder,
3376 match_end,
3377 match_start);
3378 }
3379 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003380 HandleScope loop_scope(isolate);
3381 builder->Add(*isolate->factory()->NewSubString(subject,
3382 match_start,
3383 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003384 if (match_start != match_end) {
3385 pos = match_end;
3386 } else {
3387 pos = match_end + 1;
3388 if (pos > subject_length) break;
3389 }
3390 } else if (result == RegExpImpl::RE_FAILURE) {
3391 break;
3392 } else {
3393 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3394 return result;
3395 }
3396 }
3397
3398 if (match_start >= 0) {
3399 if (match_end < subject_length) {
3400 ReplacementStringBuilder::AddSubjectSlice(builder,
3401 match_end,
3402 subject_length);
3403 }
3404 SetLastMatchInfoNoCaptures(subject,
3405 last_match_array,
3406 match_start,
3407 match_end);
3408 return RegExpImpl::RE_SUCCESS;
3409 } else {
3410 return RegExpImpl::RE_FAILURE; // No matches at all.
3411 }
3412}
3413
3414
3415static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003416 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003417 Handle<String> subject,
3418 Handle<JSRegExp> regexp,
3419 Handle<JSArray> last_match_array,
3420 FixedArrayBuilder* builder) {
3421
3422 ASSERT(subject->IsFlat());
3423 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3424 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3425
3426 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003427 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003428
3429 RegExpImpl::IrregexpResult result =
3430 RegExpImpl::IrregexpExecOnce(regexp,
3431 subject,
3432 0,
3433 register_vector);
3434
3435 int capture_count = regexp->CaptureCount();
3436 int subject_length = subject->length();
3437
3438 // Position to search from.
3439 int pos = 0;
3440 // End of previous match. Differs from pos if match was empty.
3441 int match_end = 0;
3442 if (result == RegExpImpl::RE_SUCCESS) {
3443 // Need to keep a copy of the previous match for creating last_match_info
3444 // at the end, so we have two vectors that we swap between.
3445 OffsetsVector registers2(required_registers);
3446 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3447
3448 do {
3449 int match_start = register_vector[0];
3450 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3451 if (match_end < match_start) {
3452 ReplacementStringBuilder::AddSubjectSlice(builder,
3453 match_end,
3454 match_start);
3455 }
3456 match_end = register_vector[1];
3457
3458 {
3459 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003460 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003461 // Arguments array to replace function is match, captures, index and
3462 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003463 Handle<FixedArray> elements =
3464 isolate->factory()->NewFixedArray(3 + capture_count);
3465 Handle<String> match = isolate->factory()->NewSubString(subject,
3466 match_start,
3467 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003468 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003469 for (int i = 1; i <= capture_count; i++) {
3470 int start = register_vector[i * 2];
3471 if (start >= 0) {
3472 int end = register_vector[i * 2 + 1];
3473 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003474 Handle<String> substring = isolate->factory()->NewSubString(subject,
3475 start,
3476 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003477 elements->set(i, *substring);
3478 } else {
3479 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003480 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003481 }
3482 }
3483 elements->set(capture_count + 1, Smi::FromInt(match_start));
3484 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003485 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003486 }
3487 // Swap register vectors, so the last successful match is in
3488 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003489 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003490 prev_register_vector = register_vector;
3491 register_vector = tmp;
3492
3493 if (match_end > match_start) {
3494 pos = match_end;
3495 } else {
3496 pos = match_end + 1;
3497 if (pos > subject_length) {
3498 break;
3499 }
3500 }
3501
3502 result = RegExpImpl::IrregexpExecOnce(regexp,
3503 subject,
3504 pos,
3505 register_vector);
3506 } while (result == RegExpImpl::RE_SUCCESS);
3507
3508 if (result != RegExpImpl::RE_EXCEPTION) {
3509 // Finished matching, with at least one match.
3510 if (match_end < subject_length) {
3511 ReplacementStringBuilder::AddSubjectSlice(builder,
3512 match_end,
3513 subject_length);
3514 }
3515
3516 int last_match_capture_count = (capture_count + 1) * 2;
3517 int last_match_array_size =
3518 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3519 last_match_array->EnsureSize(last_match_array_size);
3520 AssertNoAllocation no_gc;
3521 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3522 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3523 RegExpImpl::SetLastSubject(elements, *subject);
3524 RegExpImpl::SetLastInput(elements, *subject);
3525 for (int i = 0; i < last_match_capture_count; i++) {
3526 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3527 }
3528 return RegExpImpl::RE_SUCCESS;
3529 }
3530 }
3531 // No matches at all, return failure or exception result directly.
3532 return result;
3533}
3534
3535
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003536static MaybeObject* Runtime_RegExpExecMultiple(RUNTIME_CALLING_CONVENTION) {
3537 RUNTIME_GET_ISOLATE;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003538 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003539 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003540
3541 CONVERT_ARG_CHECKED(String, subject, 1);
3542 if (!subject->IsFlat()) { FlattenString(subject); }
3543 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3544 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3545 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3546
3547 ASSERT(last_match_info->HasFastElements());
3548 ASSERT(regexp->GetFlags().is_global());
3549 Handle<FixedArray> result_elements;
3550 if (result_array->HasFastElements()) {
3551 result_elements =
3552 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3553 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003554 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003555 }
3556 FixedArrayBuilder builder(result_elements);
3557
3558 if (regexp->TypeTag() == JSRegExp::ATOM) {
3559 Handle<String> pattern(
3560 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003561 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003562 if (SearchStringMultiple(isolate, subject, pattern,
3563 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003564 return *builder.ToJSArray(result_array);
3565 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003566 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003567 }
3568
3569 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3570
3571 RegExpImpl::IrregexpResult result;
3572 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003573 result = SearchRegExpNoCaptureMultiple(isolate,
3574 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003575 regexp,
3576 last_match_info,
3577 &builder);
3578 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003579 result = SearchRegExpMultiple(isolate,
3580 subject,
3581 regexp,
3582 last_match_info,
3583 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003584 }
3585 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003586 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003587 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3588 return Failure::Exception();
3589}
3590
3591
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003592static MaybeObject* Runtime_NumberToRadixString(RUNTIME_CALLING_CONVENTION) {
3593 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003594 NoHandleAllocation ha;
3595 ASSERT(args.length() == 2);
3596
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003597 // Fast case where the result is a one character string.
3598 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3599 int value = Smi::cast(args[0])->value();
3600 int radix = Smi::cast(args[1])->value();
3601 if (value >= 0 && value < radix) {
3602 RUNTIME_ASSERT(radix <= 36);
3603 // Character array used for conversion.
3604 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003605 return isolate->heap()->
3606 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003607 }
3608 }
3609
3610 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003611 CONVERT_DOUBLE_CHECKED(value, args[0]);
3612 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003613 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003614 }
3615 if (isinf(value)) {
3616 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003617 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003618 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003619 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620 }
3621 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3622 int radix = FastD2I(radix_number);
3623 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3624 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003625 MaybeObject* result =
3626 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003627 DeleteArray(str);
3628 return result;
3629}
3630
3631
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003632static MaybeObject* Runtime_NumberToFixed(RUNTIME_CALLING_CONVENTION) {
3633 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003634 NoHandleAllocation ha;
3635 ASSERT(args.length() == 2);
3636
3637 CONVERT_DOUBLE_CHECKED(value, args[0]);
3638 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003639 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003640 }
3641 if (isinf(value)) {
3642 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003643 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003644 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003645 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003646 }
3647 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3648 int f = FastD2I(f_number);
3649 RUNTIME_ASSERT(f >= 0);
3650 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003651 MaybeObject* res =
3652 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003653 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003654 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003655}
3656
3657
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003658static MaybeObject* Runtime_NumberToExponential(RUNTIME_CALLING_CONVENTION) {
3659 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003660 NoHandleAllocation ha;
3661 ASSERT(args.length() == 2);
3662
3663 CONVERT_DOUBLE_CHECKED(value, args[0]);
3664 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003665 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003666 }
3667 if (isinf(value)) {
3668 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003669 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003670 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003671 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003672 }
3673 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3674 int f = FastD2I(f_number);
3675 RUNTIME_ASSERT(f >= -1 && f <= 20);
3676 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003677 MaybeObject* res =
3678 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003679 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003680 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003681}
3682
3683
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003684static MaybeObject* Runtime_NumberToPrecision(RUNTIME_CALLING_CONVENTION) {
3685 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003686 NoHandleAllocation ha;
3687 ASSERT(args.length() == 2);
3688
3689 CONVERT_DOUBLE_CHECKED(value, args[0]);
3690 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003691 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003692 }
3693 if (isinf(value)) {
3694 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003695 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003696 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003697 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003698 }
3699 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3700 int f = FastD2I(f_number);
3701 RUNTIME_ASSERT(f >= 1 && f <= 21);
3702 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003703 MaybeObject* res =
3704 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003705 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003706 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003707}
3708
3709
3710// Returns a single character string where first character equals
3711// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003712static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003713 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003714 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003715 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003716 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003717 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003718 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003719}
3720
3721
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003722MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3723 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003724 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003725 // Handle [] indexing on Strings
3726 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003727 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3728 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003729 }
3730
3731 // Handle [] indexing on String objects
3732 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003733 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3734 Handle<Object> result =
3735 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3736 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003737 }
3738
3739 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003740 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003741 return prototype->GetElement(index);
3742 }
3743
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003744 return GetElement(object, index);
3745}
3746
3747
lrn@chromium.org303ada72010-10-27 09:33:13 +00003748MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003749 return object->GetElement(index);
3750}
3751
3752
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003753MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3754 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003755 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003756 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003757
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003758 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003759 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003760 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003761 isolate->factory()->NewTypeError("non_object_property_load",
3762 HandleVector(args, 2));
3763 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003764 }
3765
3766 // Check if the given key is an array index.
3767 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003768 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003769 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003770 }
3771
3772 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003773 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003774 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003775 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003776 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003777 bool has_pending_exception = false;
3778 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003779 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003780 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003781 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003782 }
3783
ager@chromium.org32912102009-01-16 10:38:43 +00003784 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003785 // the element if so.
3786 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003787 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003788 } else {
3789 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003790 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003791 }
3792}
3793
3794
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003795static MaybeObject* Runtime_GetProperty(RUNTIME_CALLING_CONVENTION) {
3796 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003797 NoHandleAllocation ha;
3798 ASSERT(args.length() == 2);
3799
3800 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003801 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003802
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003803 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003804}
3805
3806
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003807// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003808static MaybeObject* Runtime_KeyedGetProperty(RUNTIME_CALLING_CONVENTION) {
3809 RUNTIME_GET_ISOLATE;
ager@chromium.org7c537e22008-10-16 08:43:32 +00003810 NoHandleAllocation ha;
3811 ASSERT(args.length() == 2);
3812
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003813 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003814 // itself.
3815 //
3816 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003817 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003818 // global proxy object never has properties. This is the case
3819 // because the global proxy object forwards everything to its hidden
3820 // prototype including local lookups.
3821 //
3822 // Additionally, we need to make sure that we do not cache results
3823 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003824 if (args[0]->IsJSObject() &&
3825 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003826 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003827 args[1]->IsString()) {
3828 JSObject* receiver = JSObject::cast(args[0]);
3829 String* key = String::cast(args[1]);
3830 if (receiver->HasFastProperties()) {
3831 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003832 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003833 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3834 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003835 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003836 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003837 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003838 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003839 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003840 LookupResult result;
3841 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003842 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003843 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003844 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003845 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003846 }
3847 } else {
3848 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003849 StringDictionary* dictionary = receiver->property_dictionary();
3850 int entry = dictionary->FindEntry(key);
3851 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003852 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003853 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003854 if (!receiver->IsGlobalObject()) return value;
3855 value = JSGlobalPropertyCell::cast(value)->value();
3856 if (!value->IsTheHole()) return value;
3857 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003858 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003859 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003860 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3861 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003862 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003863 Handle<String> str = args.at<String>(0);
3864 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003865 if (index >= 0 && index < str->length()) {
3866 Handle<Object> result = GetCharAt(str, index);
3867 return *result;
3868 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003869 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003870
3871 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003872 return Runtime::GetObjectProperty(isolate,
3873 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003874 args.at<Object>(1));
3875}
3876
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003877// Implements part of 8.12.9 DefineOwnProperty.
3878// There are 3 cases that lead here:
3879// Step 4b - define a new accessor property.
3880// Steps 9c & 12 - replace an existing data property with an accessor property.
3881// Step 12 - update an existing accessor property with an accessor or generic
3882// descriptor.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003883static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(
3884 RUNTIME_CALLING_CONVENTION) {
3885 RUNTIME_GET_ISOLATE;
ager@chromium.org5c838252010-02-19 08:53:10 +00003886 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003887 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003888 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3889 CONVERT_CHECKED(String, name, args[1]);
3890 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003891 Object* fun = args[3];
3892 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003893 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3894 int unchecked = flag_attr->value();
3895 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3896 RUNTIME_ASSERT(!obj->IsNull());
3897 LookupResult result;
3898 obj->LocalLookupRealNamedProperty(name, &result);
3899
3900 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3901 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3902 // delete it to avoid running into trouble in DefineAccessor, which
3903 // handles this incorrectly if the property is readonly (does nothing)
3904 if (result.IsProperty() &&
3905 (result.type() == FIELD || result.type() == NORMAL
3906 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003907 Object* ok;
3908 { MaybeObject* maybe_ok =
3909 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3910 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3911 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003912 }
3913 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3914}
3915
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003916// Implements part of 8.12.9 DefineOwnProperty.
3917// There are 3 cases that lead here:
3918// Step 4a - define a new data property.
3919// Steps 9b & 12 - replace an existing accessor property with a data property.
3920// Step 12 - update an existing data property with a data or generic
3921// descriptor.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003922static MaybeObject* Runtime_DefineOrRedefineDataProperty(
3923 RUNTIME_CALLING_CONVENTION) {
3924 RUNTIME_GET_ISOLATE;
ager@chromium.org5c838252010-02-19 08:53:10 +00003925 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003926 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003927 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3928 CONVERT_ARG_CHECKED(String, name, 1);
3929 Handle<Object> obj_value = args.at<Object>(2);
3930
3931 CONVERT_CHECKED(Smi, flag, args[3]);
3932 int unchecked = flag->value();
3933 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3934
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003935 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3936
3937 // Check if this is an element.
3938 uint32_t index;
3939 bool is_element = name->AsArrayIndex(&index);
3940
3941 // Special case for elements if any of the flags are true.
3942 // If elements are in fast case we always implicitly assume that:
3943 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3944 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3945 is_element) {
3946 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003947 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003948 // We do not need to do access checks here since these has already
3949 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003950 Handle<Object> proto(js_object->GetPrototype());
3951 // If proxy is detached, ignore the assignment. Alternatively,
3952 // we could throw an exception.
3953 if (proto->IsNull()) return *obj_value;
3954 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003955 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003956 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003957 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003958 // Make sure that we never go back to fast case.
3959 dictionary->set_requires_slow_elements();
3960 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003961 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003962 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003963 }
3964
ager@chromium.org5c838252010-02-19 08:53:10 +00003965 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003966 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003967
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003968 // To be compatible with safari we do not change the value on API objects
3969 // in defineProperty. Firefox disagrees here, and actually changes the value.
3970 if (result.IsProperty() &&
3971 (result.type() == CALLBACKS) &&
3972 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003973 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003974 }
3975
ager@chromium.org5c838252010-02-19 08:53:10 +00003976 // Take special care when attributes are different and there is already
3977 // a property. For simplicity we normalize the property which enables us
3978 // to not worry about changing the instance_descriptor and creating a new
3979 // map. The current version of SetObjectProperty does not handle attributes
3980 // correctly in the case where a property is a field and is reset with
3981 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003982 if (result.IsProperty() &&
3983 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003984 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003985 if (js_object->IsJSGlobalProxy()) {
3986 // Since the result is a property, the prototype will exist so
3987 // we don't have to check for null.
3988 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003989 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003990 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003991 // Use IgnoreAttributes version since a readonly property may be
3992 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003993 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3994 *obj_value,
3995 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003996 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003997
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003998 return Runtime::ForceSetObjectProperty(isolate,
3999 js_object,
4000 name,
4001 obj_value,
4002 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004003}
4004
4005
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004006MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4007 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004008 Handle<Object> key,
4009 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004010 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004011 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004012 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004013
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004015 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004016 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004017 isolate->factory()->NewTypeError("non_object_property_store",
4018 HandleVector(args, 2));
4019 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004020 }
4021
4022 // If the object isn't a JavaScript object, we ignore the store.
4023 if (!object->IsJSObject()) return *value;
4024
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004025 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4026
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004027 // Check if the given key is an array index.
4028 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004029 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004030 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4031 // of a string using [] notation. We need to support this too in
4032 // JavaScript.
4033 // In the case of a String object we just need to redirect the assignment to
4034 // the underlying string if the index is in range. Since the underlying
4035 // string does nothing with the assignment then we can ignore such
4036 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004037 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004038 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004039 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004040
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004041 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004042 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004043 return *value;
4044 }
4045
4046 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004047 Handle<Object> result;
4048 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004049 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004050 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004051 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004052 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004053 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004055 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056 return *value;
4057 }
4058
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004059 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004060 bool has_pending_exception = false;
4061 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4062 if (has_pending_exception) return Failure::Exception();
4063 Handle<String> name = Handle<String>::cast(converted);
4064
4065 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004066 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004067 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004068 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 }
4070}
4071
4072
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004073MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4074 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004075 Handle<Object> key,
4076 Handle<Object> value,
4077 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004078 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004079
4080 // Check if the given key is an array index.
4081 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004082 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004083 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4084 // of a string using [] notation. We need to support this too in
4085 // JavaScript.
4086 // In the case of a String object we just need to redirect the assignment to
4087 // the underlying string if the index is in range. Since the underlying
4088 // string does nothing with the assignment then we can ignore such
4089 // assignments.
4090 if (js_object->IsStringObjectWithCharacterAt(index)) {
4091 return *value;
4092 }
4093
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004094 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004095 }
4096
4097 if (key->IsString()) {
4098 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004099 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004100 } else {
4101 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004102 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004103 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4104 *value,
4105 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004106 }
4107 }
4108
4109 // Call-back into JavaScript to convert the key to a string.
4110 bool has_pending_exception = false;
4111 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4112 if (has_pending_exception) return Failure::Exception();
4113 Handle<String> name = Handle<String>::cast(converted);
4114
4115 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004116 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004117 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004118 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004119 }
4120}
4121
4122
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004123MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4124 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004125 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004126 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004127
4128 // Check if the given key is an array index.
4129 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004130 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004131 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4132 // characters of a string using [] notation. In the case of a
4133 // String object we just need to redirect the deletion to the
4134 // underlying string if the index is in range. Since the
4135 // underlying string does nothing with the deletion, we can ignore
4136 // such deletions.
4137 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004138 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004139 }
4140
4141 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4142 }
4143
4144 Handle<String> key_string;
4145 if (key->IsString()) {
4146 key_string = Handle<String>::cast(key);
4147 } else {
4148 // Call-back into JavaScript to convert the key to a string.
4149 bool has_pending_exception = false;
4150 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4151 if (has_pending_exception) return Failure::Exception();
4152 key_string = Handle<String>::cast(converted);
4153 }
4154
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004155 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004156 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4157}
4158
4159
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004160static MaybeObject* Runtime_SetProperty(RUNTIME_CALLING_CONVENTION) {
4161 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004162 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004163 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164
4165 Handle<Object> object = args.at<Object>(0);
4166 Handle<Object> key = args.at<Object>(1);
4167 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004168 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4169 RUNTIME_ASSERT(
4170 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004171 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004172 PropertyAttributes attributes =
4173 static_cast<PropertyAttributes>(unchecked_attributes);
4174
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004175 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004176 if (args.length() == 5) {
4177 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4178 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4179 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004180 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004181 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004182
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004183 return Runtime::SetObjectProperty(isolate,
4184 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004185 key,
4186 value,
4187 attributes,
4188 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004189}
4190
4191
4192// Set a local property, even if it is READ_ONLY. If the property does not
4193// exist, it will be added with attributes NONE.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004194static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(
4195 RUNTIME_CALLING_CONVENTION) {
4196 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004197 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004198 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004199 CONVERT_CHECKED(JSObject, object, args[0]);
4200 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004201 // Compute attributes.
4202 PropertyAttributes attributes = NONE;
4203 if (args.length() == 4) {
4204 CONVERT_CHECKED(Smi, value_obj, args[3]);
4205 int unchecked_value = value_obj->value();
4206 // Only attribute bits should be set.
4207 RUNTIME_ASSERT(
4208 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4209 attributes = static_cast<PropertyAttributes>(unchecked_value);
4210 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004211
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004212 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004213 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004214}
4215
4216
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004217static MaybeObject* Runtime_DeleteProperty(RUNTIME_CALLING_CONVENTION) {
4218 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004219 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004220 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004221
4222 CONVERT_CHECKED(JSObject, object, args[0]);
4223 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004224 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004225 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004226 ? JSObject::STRICT_DELETION
4227 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004228}
4229
4230
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004231static Object* HasLocalPropertyImplementation(Isolate* isolate,
4232 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004233 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004234 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004235 // Handle hidden prototypes. If there's a hidden prototype above this thing
4236 // then we have to check it for properties, because they are supposed to
4237 // look like they are on this object.
4238 Handle<Object> proto(object->GetPrototype());
4239 if (proto->IsJSObject() &&
4240 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004241 return HasLocalPropertyImplementation(isolate,
4242 Handle<JSObject>::cast(proto),
4243 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004244 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004245 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004246}
4247
4248
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004249static MaybeObject* Runtime_HasLocalProperty(RUNTIME_CALLING_CONVENTION) {
4250 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004251 NoHandleAllocation ha;
4252 ASSERT(args.length() == 2);
4253 CONVERT_CHECKED(String, key, args[1]);
4254
ager@chromium.org9085a012009-05-11 19:22:57 +00004255 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004256 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004257 if (obj->IsJSObject()) {
4258 JSObject* object = JSObject::cast(obj);
4259 // Fast case - no interceptors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004260 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004261 // Slow case. Either it's not there or we have an interceptor. We should
4262 // have handles for this kind of deal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004263 HandleScope scope(isolate);
4264 return HasLocalPropertyImplementation(isolate,
4265 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004266 Handle<String>(key));
4267 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004268 // Well, there is one exception: Handle [] on strings.
4269 uint32_t index;
4270 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00004271 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00004272 if (index < static_cast<uint32_t>(string->length()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004273 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004274 }
4275 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004276 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004277}
4278
4279
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004280static MaybeObject* Runtime_HasProperty(RUNTIME_CALLING_CONVENTION) {
4281 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004282 NoHandleAllocation na;
4283 ASSERT(args.length() == 2);
4284
4285 // Only JS objects can have properties.
4286 if (args[0]->IsJSObject()) {
4287 JSObject* object = JSObject::cast(args[0]);
4288 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004289 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004290 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004291 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004292}
4293
4294
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004295static MaybeObject* Runtime_HasElement(RUNTIME_CALLING_CONVENTION) {
4296 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004297 NoHandleAllocation na;
4298 ASSERT(args.length() == 2);
4299
4300 // Only JS objects can have elements.
4301 if (args[0]->IsJSObject()) {
4302 JSObject* object = JSObject::cast(args[0]);
4303 CONVERT_CHECKED(Smi, index_obj, args[1]);
4304 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004305 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004306 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004307 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004308}
4309
4310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004311static MaybeObject* Runtime_IsPropertyEnumerable(RUNTIME_CALLING_CONVENTION) {
4312 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004313 NoHandleAllocation ha;
4314 ASSERT(args.length() == 2);
4315
4316 CONVERT_CHECKED(JSObject, object, args[0]);
4317 CONVERT_CHECKED(String, key, args[1]);
4318
4319 uint32_t index;
4320 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004321 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004322 }
4323
ager@chromium.org870a0b62008-11-04 11:43:05 +00004324 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004325 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004326}
4327
4328
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004329static MaybeObject* Runtime_GetPropertyNames(RUNTIME_CALLING_CONVENTION) {
4330 RUNTIME_GET_ISOLATE;
4331 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004332 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004333 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004334 return *GetKeysFor(object);
4335}
4336
4337
4338// Returns either a FixedArray as Runtime_GetPropertyNames,
4339// or, if the given object has an enum cache that contains
4340// all enumerable properties of the object and its prototypes
4341// have none, the map of the object. This is used to speed up
4342// the check for deletions during a for-in.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004343static MaybeObject* Runtime_GetPropertyNamesFast(RUNTIME_CALLING_CONVENTION) {
4344 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004345 ASSERT(args.length() == 1);
4346
4347 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4348
4349 if (raw_object->IsSimpleEnum()) return raw_object->map();
4350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004351 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004352 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004353 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4354 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004355
4356 // Test again, since cache may have been built by preceding call.
4357 if (object->IsSimpleEnum()) return object->map();
4358
4359 return *content;
4360}
4361
4362
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004363// Find the length of the prototype chain that is to to handled as one. If a
4364// prototype object is hidden it is to be viewed as part of the the object it
4365// is prototype for.
4366static int LocalPrototypeChainLength(JSObject* obj) {
4367 int count = 1;
4368 Object* proto = obj->GetPrototype();
4369 while (proto->IsJSObject() &&
4370 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4371 count++;
4372 proto = JSObject::cast(proto)->GetPrototype();
4373 }
4374 return count;
4375}
4376
4377
4378// Return the names of the local named properties.
4379// args[0]: object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004380static MaybeObject* Runtime_GetLocalPropertyNames(RUNTIME_CALLING_CONVENTION) {
4381 RUNTIME_GET_ISOLATE;
4382 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004383 ASSERT(args.length() == 1);
4384 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004385 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004386 }
4387 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4388
4389 // Skip the global proxy as it has no properties and always delegates to the
4390 // real global object.
4391 if (obj->IsJSGlobalProxy()) {
4392 // Only collect names if access is permitted.
4393 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004394 !isolate->MayNamedAccess(*obj,
4395 isolate->heap()->undefined_value(),
4396 v8::ACCESS_KEYS)) {
4397 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4398 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004399 }
4400 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4401 }
4402
4403 // Find the number of objects making up this.
4404 int length = LocalPrototypeChainLength(*obj);
4405
4406 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004407 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004408 int total_property_count = 0;
4409 Handle<JSObject> jsproto = obj;
4410 for (int i = 0; i < length; i++) {
4411 // Only collect names if access is permitted.
4412 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004413 !isolate->MayNamedAccess(*jsproto,
4414 isolate->heap()->undefined_value(),
4415 v8::ACCESS_KEYS)) {
4416 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4417 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004418 }
4419 int n;
4420 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4421 local_property_count[i] = n;
4422 total_property_count += n;
4423 if (i < length - 1) {
4424 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4425 }
4426 }
4427
4428 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004429 Handle<FixedArray> names =
4430 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004431
4432 // Get the property names.
4433 jsproto = obj;
4434 int proto_with_hidden_properties = 0;
4435 for (int i = 0; i < length; i++) {
4436 jsproto->GetLocalPropertyNames(*names,
4437 i == 0 ? 0 : local_property_count[i - 1]);
4438 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4439 proto_with_hidden_properties++;
4440 }
4441 if (i < length - 1) {
4442 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4443 }
4444 }
4445
4446 // Filter out name of hidden propeties object.
4447 if (proto_with_hidden_properties > 0) {
4448 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004449 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004450 names->length() - proto_with_hidden_properties);
4451 int dest_pos = 0;
4452 for (int i = 0; i < total_property_count; i++) {
4453 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004454 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004455 continue;
4456 }
4457 names->set(dest_pos++, name);
4458 }
4459 }
4460
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004461 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004462}
4463
4464
4465// Return the names of the local indexed properties.
4466// args[0]: object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004467static MaybeObject* Runtime_GetLocalElementNames(RUNTIME_CALLING_CONVENTION) {
4468 RUNTIME_GET_ISOLATE;
4469 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004470 ASSERT(args.length() == 1);
4471 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004472 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004473 }
4474 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4475
4476 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004477 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004478 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004479 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004480}
4481
4482
4483// Return information on whether an object has a named or indexed interceptor.
4484// args[0]: object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004485static MaybeObject* Runtime_GetInterceptorInfo(RUNTIME_CALLING_CONVENTION) {
4486 RUNTIME_GET_ISOLATE;
4487 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004488 ASSERT(args.length() == 1);
4489 if (!args[0]->IsJSObject()) {
4490 return Smi::FromInt(0);
4491 }
4492 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4493
4494 int result = 0;
4495 if (obj->HasNamedInterceptor()) result |= 2;
4496 if (obj->HasIndexedInterceptor()) result |= 1;
4497
4498 return Smi::FromInt(result);
4499}
4500
4501
4502// Return property names from named interceptor.
4503// args[0]: object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004504static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(
4505 RUNTIME_CALLING_CONVENTION) {
4506 RUNTIME_GET_ISOLATE;
4507 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004508 ASSERT(args.length() == 1);
4509 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4510
4511 if (obj->HasNamedInterceptor()) {
4512 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4513 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4514 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004515 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004516}
4517
4518
4519// Return element names from indexed interceptor.
4520// args[0]: object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004521static MaybeObject* Runtime_GetIndexedInterceptorElementNames(
4522 RUNTIME_CALLING_CONVENTION) {
4523 RUNTIME_GET_ISOLATE;
4524 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004525 ASSERT(args.length() == 1);
4526 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4527
4528 if (obj->HasIndexedInterceptor()) {
4529 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4530 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4531 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004532 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004533}
4534
4535
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004536static MaybeObject* Runtime_LocalKeys(RUNTIME_CALLING_CONVENTION) {
4537 RUNTIME_GET_ISOLATE;
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004538 ASSERT_EQ(args.length(), 1);
4539 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004540 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004541 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004542
4543 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004544 // Do access checks before going to the global object.
4545 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004546 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004547 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004548 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4549 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004550 }
4551
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004552 Handle<Object> proto(object->GetPrototype());
4553 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004554 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004555 object = Handle<JSObject>::cast(proto);
4556 }
4557
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004558 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4559 LOCAL_ONLY);
4560 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4561 // property array and since the result is mutable we have to create
4562 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004563 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004564 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004565 for (int i = 0; i < length; i++) {
4566 Object* entry = contents->get(i);
4567 if (entry->IsString()) {
4568 copy->set(i, entry);
4569 } else {
4570 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004571 HandleScope scope(isolate);
4572 Handle<Object> entry_handle(entry, isolate);
4573 Handle<Object> entry_str =
4574 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004575 copy->set(i, *entry_str);
4576 }
4577 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004578 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004579}
4580
4581
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004582static MaybeObject* Runtime_GetArgumentsProperty(RUNTIME_CALLING_CONVENTION) {
4583 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004584 NoHandleAllocation ha;
4585 ASSERT(args.length() == 1);
4586
4587 // Compute the frame holding the arguments.
4588 JavaScriptFrameIterator it;
4589 it.AdvanceToArgumentsFrame();
4590 JavaScriptFrame* frame = it.frame();
4591
4592 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004593 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004594
4595 // Try to convert the key to an index. If successful and within
4596 // index return the the argument from the frame.
4597 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004598 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004599 return frame->GetParameter(index);
4600 }
4601
4602 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004603 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004604 bool exception = false;
4605 Handle<Object> converted =
4606 Execution::ToString(args.at<Object>(0), &exception);
4607 if (exception) return Failure::Exception();
4608 Handle<String> key = Handle<String>::cast(converted);
4609
4610 // Try to convert the string key into an array index.
4611 if (key->AsArrayIndex(&index)) {
4612 if (index < n) {
4613 return frame->GetParameter(index);
4614 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004615 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004616 }
4617 }
4618
4619 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004620 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4621 if (key->Equals(isolate->heap()->callee_symbol())) {
4622 Object* function = frame->function();
4623 if (function->IsJSFunction() &&
4624 JSFunction::cast(function)->shared()->strict_mode()) {
4625 return isolate->Throw(*isolate->factory()->NewTypeError(
4626 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4627 }
4628 return function;
4629 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004630
4631 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004632 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004633}
4634
4635
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004636static MaybeObject* Runtime_ToFastProperties(RUNTIME_CALLING_CONVENTION) {
4637 RUNTIME_GET_ISOLATE;
4638 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004639
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004640 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004641 Handle<Object> object = args.at<Object>(0);
4642 if (object->IsJSObject()) {
4643 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004644 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004645 MaybeObject* ok = js_object->TransformToFastProperties(0);
4646 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004647 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004648 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004649 return *object;
4650}
4651
4652
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004653static MaybeObject* Runtime_ToSlowProperties(RUNTIME_CALLING_CONVENTION) {
4654 RUNTIME_GET_ISOLATE;
4655 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004656
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004657 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004658 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004659 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004660 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004661 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004662 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004663 return *object;
4664}
4665
4666
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004667static MaybeObject* Runtime_ToBool(RUNTIME_CALLING_CONVENTION) {
4668 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004669 NoHandleAllocation ha;
4670 ASSERT(args.length() == 1);
4671
4672 return args[0]->ToBoolean();
4673}
4674
4675
4676// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4677// Possible optimizations: put the type string into the oddballs.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004678static MaybeObject* Runtime_Typeof(RUNTIME_CALLING_CONVENTION) {
4679 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004680 NoHandleAllocation ha;
4681
4682 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004683 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004684 HeapObject* heap_obj = HeapObject::cast(obj);
4685
4686 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004687 if (heap_obj->map()->is_undetectable()) {
4688 return isolate->heap()->undefined_symbol();
4689 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004690
4691 InstanceType instance_type = heap_obj->map()->instance_type();
4692 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004693 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004694 }
4695
4696 switch (instance_type) {
4697 case ODDBALL_TYPE:
4698 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004699 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004700 }
4701 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004702 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004703 }
4704 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004705 return isolate->heap()->undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004706 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004707 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004708 default:
4709 // For any kind of object not handled above, the spec rule for
4710 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004711 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004712 }
4713}
4714
4715
lrn@chromium.org25156de2010-04-06 13:10:27 +00004716static bool AreDigits(const char*s, int from, int to) {
4717 for (int i = from; i < to; i++) {
4718 if (s[i] < '0' || s[i] > '9') return false;
4719 }
4720
4721 return true;
4722}
4723
4724
4725static int ParseDecimalInteger(const char*s, int from, int to) {
4726 ASSERT(to - from < 10); // Overflow is not possible.
4727 ASSERT(from < to);
4728 int d = s[from] - '0';
4729
4730 for (int i = from + 1; i < to; i++) {
4731 d = 10 * d + (s[i] - '0');
4732 }
4733
4734 return d;
4735}
4736
4737
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004738static MaybeObject* Runtime_StringToNumber(RUNTIME_CALLING_CONVENTION) {
4739 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004740 NoHandleAllocation ha;
4741 ASSERT(args.length() == 1);
4742 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004743 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004744
4745 // Fast case: short integer or some sorts of junk values.
4746 int len = subject->length();
4747 if (subject->IsSeqAsciiString()) {
4748 if (len == 0) return Smi::FromInt(0);
4749
4750 char const* data = SeqAsciiString::cast(subject)->GetChars();
4751 bool minus = (data[0] == '-');
4752 int start_pos = (minus ? 1 : 0);
4753
4754 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004755 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004756 } else if (data[start_pos] > '9') {
4757 // Fast check for a junk value. A valid string may start from a
4758 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4759 // the 'I' character ('Infinity'). All of that have codes not greater than
4760 // '9' except 'I'.
4761 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004762 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004763 }
4764 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4765 // The maximal/minimal smi has 10 digits. If the string has less digits we
4766 // know it will fit into the smi-data type.
4767 int d = ParseDecimalInteger(data, start_pos, len);
4768 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004769 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004770 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004771 } else if (!subject->HasHashCode() &&
4772 len <= String::kMaxArrayIndexSize &&
4773 (len == 1 || data[0] != '0')) {
4774 // String hash is not calculated yet but all the data are present.
4775 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004776 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004777#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004778 subject->Hash(); // Force hash calculation.
4779 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4780 static_cast<int>(hash));
4781#endif
4782 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004783 }
4784 return Smi::FromInt(d);
4785 }
4786 }
4787
4788 // Slower case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004789 return isolate->heap()->NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004790}
4791
4792
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004793static MaybeObject* Runtime_StringFromCharCodeArray(
4794 RUNTIME_CALLING_CONVENTION) {
4795 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004796 NoHandleAllocation ha;
4797 ASSERT(args.length() == 1);
4798
4799 CONVERT_CHECKED(JSArray, codes, args[0]);
4800 int length = Smi::cast(codes->length())->value();
4801
4802 // Check if the string can be ASCII.
4803 int i;
4804 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004805 Object* element;
4806 { MaybeObject* maybe_element = codes->GetElement(i);
4807 // We probably can't get an exception here, but just in order to enforce
4808 // the checking of inputs in the runtime calls we check here.
4809 if (!maybe_element->ToObject(&element)) return maybe_element;
4810 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004811 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4812 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4813 break;
4814 }
4815
lrn@chromium.org303ada72010-10-27 09:33:13 +00004816 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004817 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004818 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004819 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004820 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004821 }
4822
lrn@chromium.org303ada72010-10-27 09:33:13 +00004823 Object* object = NULL;
4824 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004825 String* result = String::cast(object);
4826 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004827 Object* element;
4828 { MaybeObject* maybe_element = codes->GetElement(i);
4829 if (!maybe_element->ToObject(&element)) return maybe_element;
4830 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004832 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004833 }
4834 return result;
4835}
4836
4837
4838// kNotEscaped is generated by the following:
4839//
4840// #!/bin/perl
4841// for (my $i = 0; $i < 256; $i++) {
4842// print "\n" if $i % 16 == 0;
4843// my $c = chr($i);
4844// my $escaped = 1;
4845// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4846// print $escaped ? "0, " : "1, ";
4847// }
4848
4849
4850static bool IsNotEscaped(uint16_t character) {
4851 // Only for 8 bit characters, the rest are always escaped (in a different way)
4852 ASSERT(character < 256);
4853 static const char kNotEscaped[256] = {
4854 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4855 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4856 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4857 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4858 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4859 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4860 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4861 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4862 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4863 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4864 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4865 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4866 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4867 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4868 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4869 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4870 };
4871 return kNotEscaped[character] != 0;
4872}
4873
4874
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004875static MaybeObject* Runtime_URIEscape(RUNTIME_CALLING_CONVENTION) {
4876 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004877 const char hex_chars[] = "0123456789ABCDEF";
4878 NoHandleAllocation ha;
4879 ASSERT(args.length() == 1);
4880 CONVERT_CHECKED(String, source, args[0]);
4881
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004882 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004883
4884 int escaped_length = 0;
4885 int length = source->length();
4886 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004887 Access<StringInputBuffer> buffer(
4888 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004889 buffer->Reset(source);
4890 while (buffer->has_more()) {
4891 uint16_t character = buffer->GetNext();
4892 if (character >= 256) {
4893 escaped_length += 6;
4894 } else if (IsNotEscaped(character)) {
4895 escaped_length++;
4896 } else {
4897 escaped_length += 3;
4898 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004899 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004900 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004901 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004902 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004903 return Failure::OutOfMemoryException();
4904 }
4905 }
4906 }
4907 // No length change implies no change. Return original string if no change.
4908 if (escaped_length == length) {
4909 return source;
4910 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004911 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004912 { MaybeObject* maybe_o =
4913 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004914 if (!maybe_o->ToObject(&o)) return maybe_o;
4915 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004916 String* destination = String::cast(o);
4917 int dest_position = 0;
4918
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004919 Access<StringInputBuffer> buffer(
4920 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004921 buffer->Rewind();
4922 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004923 uint16_t chr = buffer->GetNext();
4924 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004925 destination->Set(dest_position, '%');
4926 destination->Set(dest_position+1, 'u');
4927 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4928 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4929 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4930 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004931 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004932 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004933 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004934 dest_position++;
4935 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004936 destination->Set(dest_position, '%');
4937 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4938 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004939 dest_position += 3;
4940 }
4941 }
4942 return destination;
4943}
4944
4945
4946static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4947 static const signed char kHexValue['g'] = {
4948 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4949 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4950 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4951 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4952 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4953 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4954 -1, 10, 11, 12, 13, 14, 15 };
4955
4956 if (character1 > 'f') return -1;
4957 int hi = kHexValue[character1];
4958 if (hi == -1) return -1;
4959 if (character2 > 'f') return -1;
4960 int lo = kHexValue[character2];
4961 if (lo == -1) return -1;
4962 return (hi << 4) + lo;
4963}
4964
4965
ager@chromium.org870a0b62008-11-04 11:43:05 +00004966static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004967 int i,
4968 int length,
4969 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004970 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004971 int32_t hi = 0;
4972 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004973 if (character == '%' &&
4974 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004975 source->Get(i + 1) == 'u' &&
4976 (hi = TwoDigitHex(source->Get(i + 2),
4977 source->Get(i + 3))) != -1 &&
4978 (lo = TwoDigitHex(source->Get(i + 4),
4979 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004980 *step = 6;
4981 return (hi << 8) + lo;
4982 } else if (character == '%' &&
4983 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004984 (lo = TwoDigitHex(source->Get(i + 1),
4985 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004986 *step = 3;
4987 return lo;
4988 } else {
4989 *step = 1;
4990 return character;
4991 }
4992}
4993
4994
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004995static MaybeObject* Runtime_URIUnescape(RUNTIME_CALLING_CONVENTION) {
4996 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004997 NoHandleAllocation ha;
4998 ASSERT(args.length() == 1);
4999 CONVERT_CHECKED(String, source, args[0]);
5000
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005001 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005002
5003 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005004 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005005
5006 int unescaped_length = 0;
5007 for (int i = 0; i < length; unescaped_length++) {
5008 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005009 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005010 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005011 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005012 i += step;
5013 }
5014
5015 // No length change implies no change. Return original string if no change.
5016 if (unescaped_length == length)
5017 return source;
5018
lrn@chromium.org303ada72010-10-27 09:33:13 +00005019 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005020 { MaybeObject* maybe_o =
5021 ascii ?
5022 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5023 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005024 if (!maybe_o->ToObject(&o)) return maybe_o;
5025 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005026 String* destination = String::cast(o);
5027
5028 int dest_position = 0;
5029 for (int i = 0; i < length; dest_position++) {
5030 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005031 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005032 i += step;
5033 }
5034 return destination;
5035}
5036
5037
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005038static const unsigned int kQuoteTableLength = 128u;
5039
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005040static const int kJsonQuotesCharactersPerEntry = 8;
5041static const char* const JsonQuotes =
5042 "\\u0000 \\u0001 \\u0002 \\u0003 "
5043 "\\u0004 \\u0005 \\u0006 \\u0007 "
5044 "\\b \\t \\n \\u000b "
5045 "\\f \\r \\u000e \\u000f "
5046 "\\u0010 \\u0011 \\u0012 \\u0013 "
5047 "\\u0014 \\u0015 \\u0016 \\u0017 "
5048 "\\u0018 \\u0019 \\u001a \\u001b "
5049 "\\u001c \\u001d \\u001e \\u001f "
5050 " ! \\\" # "
5051 "$ % & ' "
5052 "( ) * + "
5053 ", - . / "
5054 "0 1 2 3 "
5055 "4 5 6 7 "
5056 "8 9 : ; "
5057 "< = > ? "
5058 "@ A B C "
5059 "D E F G "
5060 "H I J K "
5061 "L M N O "
5062 "P Q R S "
5063 "T U V W "
5064 "X Y Z [ "
5065 "\\\\ ] ^ _ "
5066 "` a b c "
5067 "d e f g "
5068 "h i j k "
5069 "l m n o "
5070 "p q r s "
5071 "t u v w "
5072 "x y z { "
5073 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005074
5075
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005076// For a string that is less than 32k characters it should always be
5077// possible to allocate it in new space.
5078static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5079
5080
5081// Doing JSON quoting cannot make the string more than this many times larger.
5082static const int kJsonQuoteWorstCaseBlowup = 6;
5083
5084
5085// Covers the entire ASCII range (all other characters are unchanged by JSON
5086// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005087static const byte JsonQuoteLengths[kQuoteTableLength] = {
5088 6, 6, 6, 6, 6, 6, 6, 6,
5089 2, 2, 2, 6, 2, 2, 6, 6,
5090 6, 6, 6, 6, 6, 6, 6, 6,
5091 6, 6, 6, 6, 6, 6, 6, 6,
5092 1, 1, 2, 1, 1, 1, 1, 1,
5093 1, 1, 1, 1, 1, 1, 1, 1,
5094 1, 1, 1, 1, 1, 1, 1, 1,
5095 1, 1, 1, 1, 1, 1, 1, 1,
5096 1, 1, 1, 1, 1, 1, 1, 1,
5097 1, 1, 1, 1, 1, 1, 1, 1,
5098 1, 1, 1, 1, 1, 1, 1, 1,
5099 1, 1, 1, 1, 2, 1, 1, 1,
5100 1, 1, 1, 1, 1, 1, 1, 1,
5101 1, 1, 1, 1, 1, 1, 1, 1,
5102 1, 1, 1, 1, 1, 1, 1, 1,
5103 1, 1, 1, 1, 1, 1, 1, 1,
5104};
5105
5106
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005107template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005108MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005109
5110
5111template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005112MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5113 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005114}
5115
5116
5117template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005118MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5119 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005120}
5121
5122
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005123template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005124static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5125 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005126 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005127 const Char* read_cursor = characters.start();
5128 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005129 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005130 int quoted_length = kSpaceForQuotes;
5131 while (read_cursor < end) {
5132 Char c = *(read_cursor++);
5133 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5134 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005135 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005136 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005137 }
5138 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005139 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5140 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005141 Object* new_object;
5142 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005143 return new_alloc;
5144 }
5145 StringType* new_string = StringType::cast(new_object);
5146
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005147 Char* write_cursor = reinterpret_cast<Char*>(
5148 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005149 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005150 *(write_cursor++) = '"';
5151
5152 read_cursor = characters.start();
5153 while (read_cursor < end) {
5154 Char c = *(read_cursor++);
5155 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5156 *(write_cursor++) = c;
5157 } else {
5158 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5159 const char* replacement = JsonQuotes +
5160 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5161 for (int i = 0; i < len; i++) {
5162 *write_cursor++ = *replacement++;
5163 }
5164 }
5165 }
5166 *(write_cursor++) = '"';
5167 return new_string;
5168}
5169
5170
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005171template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005172static MaybeObject* QuoteJsonString(Isolate* isolate,
5173 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005174 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005175 isolate->counters()->quote_json_char_count()->Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005176 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005177 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
5178 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005179 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005180 }
5181
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005182 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5183 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005184 Object* new_object;
5185 if (!new_alloc->ToObject(&new_object)) {
5186 return new_alloc;
5187 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005188 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005189 // Even if our string is small enough to fit in new space we still have to
5190 // handle it being allocated in old space as may happen in the third
5191 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5192 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005193 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005194 }
5195 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005196 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005197
5198 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5199 Char* write_cursor = reinterpret_cast<Char*>(
5200 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005201 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005202 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005203
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005204 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005205 const Char* end = read_cursor + length;
5206 while (read_cursor < end) {
5207 Char c = *(read_cursor++);
5208 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5209 *(write_cursor++) = c;
5210 } else {
5211 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5212 const char* replacement = JsonQuotes +
5213 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5214 write_cursor[0] = replacement[0];
5215 if (len > 1) {
5216 write_cursor[1] = replacement[1];
5217 if (len > 2) {
5218 ASSERT(len == 6);
5219 write_cursor[2] = replacement[2];
5220 write_cursor[3] = replacement[3];
5221 write_cursor[4] = replacement[4];
5222 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005223 }
5224 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005225 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005226 }
5227 }
5228 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005229
5230 int final_length = static_cast<int>(
5231 write_cursor - reinterpret_cast<Char*>(
5232 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005233 isolate->heap()->new_space()->
5234 template ShrinkStringAtAllocationBoundary<StringType>(
5235 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005236 return new_string;
5237}
5238
5239
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005240static MaybeObject* Runtime_QuoteJSONString(RUNTIME_CALLING_CONVENTION) {
5241 RUNTIME_GET_ISOLATE;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005242 NoHandleAllocation ha;
5243 CONVERT_CHECKED(String, str, args[0]);
5244 if (!str->IsFlat()) {
5245 MaybeObject* try_flatten = str->TryFlatten();
5246 Object* flat;
5247 if (!try_flatten->ToObject(&flat)) {
5248 return try_flatten;
5249 }
5250 str = String::cast(flat);
5251 ASSERT(str->IsFlat());
5252 }
5253 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005254 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5255 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005256 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005257 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5258 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005259 }
5260}
5261
5262
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005263static MaybeObject* Runtime_QuoteJSONStringComma(RUNTIME_CALLING_CONVENTION) {
5264 RUNTIME_GET_ISOLATE;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005265 NoHandleAllocation ha;
5266 CONVERT_CHECKED(String, str, args[0]);
5267 if (!str->IsFlat()) {
5268 MaybeObject* try_flatten = str->TryFlatten();
5269 Object* flat;
5270 if (!try_flatten->ToObject(&flat)) {
5271 return try_flatten;
5272 }
5273 str = String::cast(flat);
5274 ASSERT(str->IsFlat());
5275 }
5276 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005277 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5278 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005279 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005280 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5281 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005282 }
5283}
5284
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005285static MaybeObject* Runtime_StringParseInt(RUNTIME_CALLING_CONVENTION) {
5286 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005287 NoHandleAllocation ha;
5288
5289 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005290 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005291
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005292 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005293
lrn@chromium.org25156de2010-04-06 13:10:27 +00005294 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
5295 double value = StringToInt(s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005296 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005297}
5298
5299
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005300static MaybeObject* Runtime_StringParseFloat(RUNTIME_CALLING_CONVENTION) {
5301 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005302 NoHandleAllocation ha;
5303 CONVERT_CHECKED(String, str, args[0]);
5304
5305 // ECMA-262 section 15.1.2.3, empty string is NaN
5306 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
5307
5308 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005309 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005310}
5311
5312
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005313template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005314MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005315 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005316 String* s,
5317 int length,
5318 int input_string_length,
5319 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005320 // We try this twice, once with the assumption that the result is no longer
5321 // than the input and, if that assumption breaks, again with the exact
5322 // length. This may not be pretty, but it is nicer than what was here before
5323 // and I hereby claim my vaffel-is.
5324 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005325 // Allocate the resulting string.
5326 //
5327 // NOTE: This assumes that the upper/lower case of an ascii
5328 // character is also ascii. This is currently the case, but it
5329 // might break in the future if we implement more context and locale
5330 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005331 Object* o;
5332 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005333 ? isolate->heap()->AllocateRawAsciiString(length)
5334 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005335 if (!maybe_o->ToObject(&o)) return maybe_o;
5336 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005337 String* result = String::cast(o);
5338 bool has_changed_character = false;
5339
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005340 // Convert all characters to upper case, assuming that they will fit
5341 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005342 Access<StringInputBuffer> buffer(
5343 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005344 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005345 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005346 // We can assume that the string is not empty
5347 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005348 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005349 bool has_next = buffer->has_more();
5350 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005351 int char_length = mapping->get(current, next, chars);
5352 if (char_length == 0) {
5353 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005354 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005355 i++;
5356 } else if (char_length == 1) {
5357 // Common case: converting the letter resulted in one character.
5358 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005359 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005360 has_changed_character = true;
5361 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005362 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005363 // We've assumed that the result would be as long as the
5364 // input but here is a character that converts to several
5365 // characters. No matter, we calculate the exact length
5366 // of the result and try the whole thing again.
5367 //
5368 // Note that this leaves room for optimization. We could just
5369 // memcpy what we already have to the result string. Also,
5370 // the result string is the last object allocated we could
5371 // "realloc" it and probably, in the vast majority of cases,
5372 // extend the existing string to be able to hold the full
5373 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005374 int next_length = 0;
5375 if (has_next) {
5376 next_length = mapping->get(next, 0, chars);
5377 if (next_length == 0) next_length = 1;
5378 }
5379 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005380 while (buffer->has_more()) {
5381 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005382 // NOTE: we use 0 as the next character here because, while
5383 // the next character may affect what a character converts to,
5384 // it does not in any case affect the length of what it convert
5385 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005386 int char_length = mapping->get(current, 0, chars);
5387 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005388 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005389 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005390 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005391 return Failure::OutOfMemoryException();
5392 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005393 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005394 // Try again with the real length.
5395 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005396 } else {
5397 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005398 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005399 i++;
5400 }
5401 has_changed_character = true;
5402 }
5403 current = next;
5404 }
5405 if (has_changed_character) {
5406 return result;
5407 } else {
5408 // If we didn't actually change anything in doing the conversion
5409 // we simple return the result and let the converted string
5410 // become garbage; there is no reason to keep two identical strings
5411 // alive.
5412 return s;
5413 }
5414}
5415
5416
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005417namespace {
5418
lrn@chromium.org303ada72010-10-27 09:33:13 +00005419static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5420
5421
5422// Given a word and two range boundaries returns a word with high bit
5423// set in every byte iff the corresponding input byte was strictly in
5424// the range (m, n). All the other bits in the result are cleared.
5425// This function is only useful when it can be inlined and the
5426// boundaries are statically known.
5427// Requires: all bytes in the input word and the boundaries must be
5428// ascii (less than 0x7F).
5429static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5430 // Every byte in an ascii string is less than or equal to 0x7F.
5431 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5432 // Use strict inequalities since in edge cases the function could be
5433 // further simplified.
5434 ASSERT(0 < m && m < n && n < 0x7F);
5435 // Has high bit set in every w byte less than n.
5436 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5437 // Has high bit set in every w byte greater than m.
5438 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5439 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5440}
5441
5442
5443enum AsciiCaseConversion {
5444 ASCII_TO_LOWER,
5445 ASCII_TO_UPPER
5446};
5447
5448
5449template <AsciiCaseConversion dir>
5450struct FastAsciiConverter {
5451 static bool Convert(char* dst, char* src, int length) {
5452#ifdef DEBUG
5453 char* saved_dst = dst;
5454 char* saved_src = src;
5455#endif
5456 // We rely on the distance between upper and lower case letters
5457 // being a known power of 2.
5458 ASSERT('a' - 'A' == (1 << 5));
5459 // Boundaries for the range of input characters than require conversion.
5460 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5461 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5462 bool changed = false;
5463 char* const limit = src + length;
5464#ifdef V8_HOST_CAN_READ_UNALIGNED
5465 // Process the prefix of the input that requires no conversion one
5466 // (machine) word at a time.
5467 while (src <= limit - sizeof(uintptr_t)) {
5468 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5469 if (AsciiRangeMask(w, lo, hi) != 0) {
5470 changed = true;
5471 break;
5472 }
5473 *reinterpret_cast<uintptr_t*>(dst) = w;
5474 src += sizeof(uintptr_t);
5475 dst += sizeof(uintptr_t);
5476 }
5477 // Process the remainder of the input performing conversion when
5478 // required one word at a time.
5479 while (src <= limit - sizeof(uintptr_t)) {
5480 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5481 uintptr_t m = AsciiRangeMask(w, lo, hi);
5482 // The mask has high (7th) bit set in every byte that needs
5483 // conversion and we know that the distance between cases is
5484 // 1 << 5.
5485 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5486 src += sizeof(uintptr_t);
5487 dst += sizeof(uintptr_t);
5488 }
5489#endif
5490 // Process the last few bytes of the input (or the whole input if
5491 // unaligned access is not supported).
5492 while (src < limit) {
5493 char c = *src;
5494 if (lo < c && c < hi) {
5495 c ^= (1 << 5);
5496 changed = true;
5497 }
5498 *dst = c;
5499 ++src;
5500 ++dst;
5501 }
5502#ifdef DEBUG
5503 CheckConvert(saved_dst, saved_src, length, changed);
5504#endif
5505 return changed;
5506 }
5507
5508#ifdef DEBUG
5509 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5510 bool expected_changed = false;
5511 for (int i = 0; i < length; i++) {
5512 if (dst[i] == src[i]) continue;
5513 expected_changed = true;
5514 if (dir == ASCII_TO_LOWER) {
5515 ASSERT('A' <= src[i] && src[i] <= 'Z');
5516 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5517 } else {
5518 ASSERT(dir == ASCII_TO_UPPER);
5519 ASSERT('a' <= src[i] && src[i] <= 'z');
5520 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5521 }
5522 }
5523 ASSERT(expected_changed == changed);
5524 }
5525#endif
5526};
5527
5528
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005529struct ToLowerTraits {
5530 typedef unibrow::ToLowercase UnibrowConverter;
5531
lrn@chromium.org303ada72010-10-27 09:33:13 +00005532 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005533};
5534
5535
5536struct ToUpperTraits {
5537 typedef unibrow::ToUppercase UnibrowConverter;
5538
lrn@chromium.org303ada72010-10-27 09:33:13 +00005539 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005540};
5541
5542} // namespace
5543
5544
5545template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005546MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005547 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005548 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005549 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005550 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005551 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005552 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005553
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005554 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005555 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005556 if (length == 0) return s;
5557
5558 // Simpler handling of ascii strings.
5559 //
5560 // NOTE: This assumes that the upper/lower case of an ascii
5561 // character is also ascii. This is currently the case, but it
5562 // might break in the future if we implement more context and locale
5563 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005564 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005565 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005566 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005567 if (!maybe_o->ToObject(&o)) return maybe_o;
5568 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005569 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005570 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005571 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005572 return has_changed_character ? result : s;
5573 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005574
lrn@chromium.org303ada72010-10-27 09:33:13 +00005575 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005576 { MaybeObject* maybe_answer =
5577 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005578 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5579 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005580 if (answer->IsSmi()) {
5581 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005582 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005583 ConvertCaseHelper(isolate,
5584 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005585 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5586 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005587 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005588 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005589}
5590
5591
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005592static MaybeObject* Runtime_StringToLowerCase(RUNTIME_CALLING_CONVENTION) {
5593 RUNTIME_GET_ISOLATE;
5594 return ConvertCase<ToLowerTraits>(
5595 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005596}
5597
5598
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005599static MaybeObject* Runtime_StringToUpperCase(RUNTIME_CALLING_CONVENTION) {
5600 RUNTIME_GET_ISOLATE;
5601 return ConvertCase<ToUpperTraits>(
5602 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005603}
5604
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005605
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005606static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5607 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5608}
5609
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005610
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005611static MaybeObject* Runtime_StringTrim(RUNTIME_CALLING_CONVENTION) {
5612 RUNTIME_GET_ISOLATE;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005613 NoHandleAllocation ha;
5614 ASSERT(args.length() == 3);
5615
5616 CONVERT_CHECKED(String, s, args[0]);
5617 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5618 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5619
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005620 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005621 int length = s->length();
5622
5623 int left = 0;
5624 if (trimLeft) {
5625 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5626 left++;
5627 }
5628 }
5629
5630 int right = length;
5631 if (trimRight) {
5632 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5633 right--;
5634 }
5635 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005636 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005637}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005638
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005639
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005640template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005641void FindStringIndices(Isolate* isolate,
5642 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005643 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005644 ZoneList<int>* indices,
5645 unsigned int limit) {
5646 ASSERT(limit > 0);
5647 // Collect indices of pattern in subject, and the end-of-string index.
5648 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005649 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005650 int pattern_length = pattern.length();
5651 int index = 0;
5652 while (limit > 0) {
5653 index = search.Search(subject, index);
5654 if (index < 0) return;
5655 indices->Add(index);
5656 index += pattern_length;
5657 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005658 }
5659}
5660
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005661
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005662static MaybeObject* Runtime_StringSplit(RUNTIME_CALLING_CONVENTION) {
5663 RUNTIME_GET_ISOLATE;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005664 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005665 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005666 CONVERT_ARG_CHECKED(String, subject, 0);
5667 CONVERT_ARG_CHECKED(String, pattern, 1);
5668 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5669
5670 int subject_length = subject->length();
5671 int pattern_length = pattern->length();
5672 RUNTIME_ASSERT(pattern_length > 0);
5673
5674 // The limit can be very large (0xffffffffu), but since the pattern
5675 // isn't empty, we can never create more parts than ~half the length
5676 // of the subject.
5677
5678 if (!subject->IsFlat()) FlattenString(subject);
5679
5680 static const int kMaxInitialListCapacity = 16;
5681
5682 ZoneScope scope(DELETE_ON_EXIT);
5683
5684 // Find (up to limit) indices of separator and end-of-string in subject
5685 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5686 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005687 if (!pattern->IsFlat()) FlattenString(pattern);
5688
5689 // No allocation block.
5690 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005691 AssertNoAllocation nogc;
5692 if (subject->IsAsciiRepresentation()) {
5693 Vector<const char> subject_vector = subject->ToAsciiVector();
5694 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005695 FindStringIndices(isolate,
5696 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005697 pattern->ToAsciiVector(),
5698 &indices,
5699 limit);
5700 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005701 FindStringIndices(isolate,
5702 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005703 pattern->ToUC16Vector(),
5704 &indices,
5705 limit);
5706 }
5707 } else {
5708 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5709 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005710 FindStringIndices(isolate,
5711 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005712 pattern->ToAsciiVector(),
5713 &indices,
5714 limit);
5715 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005716 FindStringIndices(isolate,
5717 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005718 pattern->ToUC16Vector(),
5719 &indices,
5720 limit);
5721 }
5722 }
5723 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005724
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005725 if (static_cast<uint32_t>(indices.length()) < limit) {
5726 indices.Add(subject_length);
5727 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005728
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005729 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005730
5731 // Create JSArray of substrings separated by separator.
5732 int part_count = indices.length();
5733
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005734 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005735 result->set_length(Smi::FromInt(part_count));
5736
5737 ASSERT(result->HasFastElements());
5738
5739 if (part_count == 1 && indices.at(0) == subject_length) {
5740 FixedArray::cast(result->elements())->set(0, *subject);
5741 return *result;
5742 }
5743
5744 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5745 int part_start = 0;
5746 for (int i = 0; i < part_count; i++) {
5747 HandleScope local_loop_handle;
5748 int part_end = indices.at(i);
5749 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005750 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005751 elements->set(i, *substring);
5752 part_start = part_end + pattern_length;
5753 }
5754
5755 return *result;
5756}
5757
5758
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005759// Copies ascii characters to the given fixed array looking up
5760// one-char strings in the cache. Gives up on the first char that is
5761// not in the cache and fills the remainder with smi zeros. Returns
5762// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005763static int CopyCachedAsciiCharsToArray(Heap* heap,
5764 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005765 FixedArray* elements,
5766 int length) {
5767 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005768 FixedArray* ascii_cache = heap->single_character_string_cache();
5769 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005770 int i;
5771 for (i = 0; i < length; ++i) {
5772 Object* value = ascii_cache->get(chars[i]);
5773 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005774 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005775 elements->set(i, value, SKIP_WRITE_BARRIER);
5776 }
5777 if (i < length) {
5778 ASSERT(Smi::FromInt(0) == 0);
5779 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5780 }
5781#ifdef DEBUG
5782 for (int j = 0; j < length; ++j) {
5783 Object* element = elements->get(j);
5784 ASSERT(element == Smi::FromInt(0) ||
5785 (element->IsString() && String::cast(element)->LooksValid()));
5786 }
5787#endif
5788 return i;
5789}
5790
5791
5792// Converts a String to JSArray.
5793// For example, "foo" => ["f", "o", "o"].
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005794static MaybeObject* Runtime_StringToArray(RUNTIME_CALLING_CONVENTION) {
5795 RUNTIME_GET_ISOLATE;
5796 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005797 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005798 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005799 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005800
5801 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005802 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005803
5804 Handle<FixedArray> elements;
5805 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005806 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005807 { MaybeObject* maybe_obj =
5808 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005809 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5810 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005811 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005812
5813 Vector<const char> chars = s->ToAsciiVector();
5814 // Note, this will initialize all elements (not only the prefix)
5815 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005816 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5817 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005818 *elements,
5819 length);
5820
5821 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005822 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5823 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005824 }
5825 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005826 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005827 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005828 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5829 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005830 }
5831 }
5832
5833#ifdef DEBUG
5834 for (int i = 0; i < length; ++i) {
5835 ASSERT(String::cast(elements->get(i))->length() == 1);
5836 }
5837#endif
5838
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005839 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005840}
5841
5842
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005843static MaybeObject* Runtime_NewStringWrapper(RUNTIME_CALLING_CONVENTION) {
5844 RUNTIME_GET_ISOLATE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005845 NoHandleAllocation ha;
5846 ASSERT(args.length() == 1);
5847 CONVERT_CHECKED(String, value, args[0]);
5848 return value->ToObject();
5849}
5850
5851
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005852bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005853 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005854 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005855 return char_length == 0;
5856}
5857
5858
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005859static MaybeObject* Runtime_NumberToString(RUNTIME_CALLING_CONVENTION) {
5860 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005861 NoHandleAllocation ha;
5862 ASSERT(args.length() == 1);
5863
5864 Object* number = args[0];
5865 RUNTIME_ASSERT(number->IsNumber());
5866
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005867 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005868}
5869
5870
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005871static MaybeObject* Runtime_NumberToStringSkipCache(
5872 RUNTIME_CALLING_CONVENTION) {
5873 RUNTIME_GET_ISOLATE;
ager@chromium.org357bf652010-04-12 11:30:10 +00005874 NoHandleAllocation ha;
5875 ASSERT(args.length() == 1);
5876
5877 Object* number = args[0];
5878 RUNTIME_ASSERT(number->IsNumber());
5879
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005880 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005881}
5882
5883
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005884static MaybeObject* Runtime_NumberToInteger(RUNTIME_CALLING_CONVENTION) {
5885 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005886 NoHandleAllocation ha;
5887 ASSERT(args.length() == 1);
5888
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005889 CONVERT_DOUBLE_CHECKED(number, args[0]);
5890
5891 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5892 if (number > 0 && number <= Smi::kMaxValue) {
5893 return Smi::FromInt(static_cast<int>(number));
5894 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005895 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005896}
5897
5898
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005899static MaybeObject* Runtime_NumberToIntegerMapMinusZero(
5900 RUNTIME_CALLING_CONVENTION) {
5901 RUNTIME_GET_ISOLATE;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005902 NoHandleAllocation ha;
5903 ASSERT(args.length() == 1);
5904
5905 CONVERT_DOUBLE_CHECKED(number, args[0]);
5906
5907 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5908 if (number > 0 && number <= Smi::kMaxValue) {
5909 return Smi::FromInt(static_cast<int>(number));
5910 }
5911
5912 double double_value = DoubleToInteger(number);
5913 // Map both -0 and +0 to +0.
5914 if (double_value == 0) double_value = 0;
5915
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005916 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005917}
5918
5919
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005920static MaybeObject* Runtime_NumberToJSUint32(RUNTIME_CALLING_CONVENTION) {
5921 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005922 NoHandleAllocation ha;
5923 ASSERT(args.length() == 1);
5924
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005925 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005926 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005927}
5928
5929
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005930static MaybeObject* Runtime_NumberToJSInt32(RUNTIME_CALLING_CONVENTION) {
5931 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005932 NoHandleAllocation ha;
5933 ASSERT(args.length() == 1);
5934
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005935 CONVERT_DOUBLE_CHECKED(number, args[0]);
5936
5937 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5938 if (number > 0 && number <= Smi::kMaxValue) {
5939 return Smi::FromInt(static_cast<int>(number));
5940 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005941 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005942}
5943
5944
ager@chromium.org870a0b62008-11-04 11:43:05 +00005945// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5946// a small integer.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005947static MaybeObject* Runtime_NumberToSmi(RUNTIME_CALLING_CONVENTION) {
5948 RUNTIME_GET_ISOLATE;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005949 NoHandleAllocation ha;
5950 ASSERT(args.length() == 1);
5951
5952 Object* obj = args[0];
5953 if (obj->IsSmi()) {
5954 return obj;
5955 }
5956 if (obj->IsHeapNumber()) {
5957 double value = HeapNumber::cast(obj)->value();
5958 int int_value = FastD2I(value);
5959 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5960 return Smi::FromInt(int_value);
5961 }
5962 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005963 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005964}
5965
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005966
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005967static MaybeObject* Runtime_AllocateHeapNumber(RUNTIME_CALLING_CONVENTION) {
5968 RUNTIME_GET_ISOLATE;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005969 NoHandleAllocation ha;
5970 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005971 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005972}
5973
5974
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005975static MaybeObject* Runtime_NumberAdd(RUNTIME_CALLING_CONVENTION) {
5976 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005977 NoHandleAllocation ha;
5978 ASSERT(args.length() == 2);
5979
5980 CONVERT_DOUBLE_CHECKED(x, args[0]);
5981 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005982 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005983}
5984
5985
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005986static MaybeObject* Runtime_NumberSub(RUNTIME_CALLING_CONVENTION) {
5987 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005988 NoHandleAllocation ha;
5989 ASSERT(args.length() == 2);
5990
5991 CONVERT_DOUBLE_CHECKED(x, args[0]);
5992 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005993 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005994}
5995
5996
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005997static MaybeObject* Runtime_NumberMul(RUNTIME_CALLING_CONVENTION) {
5998 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005999 NoHandleAllocation ha;
6000 ASSERT(args.length() == 2);
6001
6002 CONVERT_DOUBLE_CHECKED(x, args[0]);
6003 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006004 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006005}
6006
6007
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006008static MaybeObject* Runtime_NumberUnaryMinus(RUNTIME_CALLING_CONVENTION) {
6009 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006010 NoHandleAllocation ha;
6011 ASSERT(args.length() == 1);
6012
6013 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006014 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006015}
6016
6017
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006018static MaybeObject* Runtime_NumberAlloc(RUNTIME_CALLING_CONVENTION) {
6019 RUNTIME_GET_ISOLATE;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006020 NoHandleAllocation ha;
6021 ASSERT(args.length() == 0);
6022
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006023 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006024}
6025
6026
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006027static MaybeObject* Runtime_NumberDiv(RUNTIME_CALLING_CONVENTION) {
6028 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006029 NoHandleAllocation ha;
6030 ASSERT(args.length() == 2);
6031
6032 CONVERT_DOUBLE_CHECKED(x, args[0]);
6033 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006034 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006035}
6036
6037
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006038static MaybeObject* Runtime_NumberMod(RUNTIME_CALLING_CONVENTION) {
6039 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040 NoHandleAllocation ha;
6041 ASSERT(args.length() == 2);
6042
6043 CONVERT_DOUBLE_CHECKED(x, args[0]);
6044 CONVERT_DOUBLE_CHECKED(y, args[1]);
6045
ager@chromium.org3811b432009-10-28 14:53:37 +00006046 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006047 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006048 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006049}
6050
6051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006052static MaybeObject* Runtime_StringAdd(RUNTIME_CALLING_CONVENTION) {
6053 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006054 NoHandleAllocation ha;
6055 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006056 CONVERT_CHECKED(String, str1, args[0]);
6057 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006058 isolate->counters()->string_add_runtime()->Increment();
6059 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006060}
6061
6062
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006063template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006064static inline void StringBuilderConcatHelper(String* special,
6065 sinkchar* sink,
6066 FixedArray* fixed_array,
6067 int array_length) {
6068 int position = 0;
6069 for (int i = 0; i < array_length; i++) {
6070 Object* element = fixed_array->get(i);
6071 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006072 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006073 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006074 int pos;
6075 int len;
6076 if (encoded_slice > 0) {
6077 // Position and length encoded in one smi.
6078 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6079 len = StringBuilderSubstringLength::decode(encoded_slice);
6080 } else {
6081 // Position and length encoded in two smis.
6082 Object* obj = fixed_array->get(++i);
6083 ASSERT(obj->IsSmi());
6084 pos = Smi::cast(obj)->value();
6085 len = -encoded_slice;
6086 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006087 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006088 sink + position,
6089 pos,
6090 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006091 position += len;
6092 } else {
6093 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006094 int element_length = string->length();
6095 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006096 position += element_length;
6097 }
6098 }
6099}
6100
6101
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006102static MaybeObject* Runtime_StringBuilderConcat(RUNTIME_CALLING_CONVENTION) {
6103 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006104 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006105 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006106 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006107 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006108 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006109 return Failure::OutOfMemoryException();
6110 }
6111 int array_length = Smi::cast(args[1])->value();
6112 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006113
6114 // This assumption is used by the slice encoding in one or two smis.
6115 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6116
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006117 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006118 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006119 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006120 }
6121 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006122 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006123 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006124 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006125
6126 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006127 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006128 } else if (array_length == 1) {
6129 Object* first = fixed_array->get(0);
6130 if (first->IsString()) return first;
6131 }
6132
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006133 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006134 int position = 0;
6135 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006136 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006137 Object* elt = fixed_array->get(i);
6138 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006139 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006140 int smi_value = Smi::cast(elt)->value();
6141 int pos;
6142 int len;
6143 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006144 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006145 pos = StringBuilderSubstringPosition::decode(smi_value);
6146 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006147 } else {
6148 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006149 len = -smi_value;
6150 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006151 i++;
6152 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006153 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006154 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006155 Object* next_smi = fixed_array->get(i);
6156 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006157 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006158 }
6159 pos = Smi::cast(next_smi)->value();
6160 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006161 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006162 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006163 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006164 ASSERT(pos >= 0);
6165 ASSERT(len >= 0);
6166 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006167 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006168 }
6169 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006170 } else if (elt->IsString()) {
6171 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006172 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006173 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006174 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006175 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006176 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006177 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006178 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006179 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006180 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006181 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006182 return Failure::OutOfMemoryException();
6183 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006184 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006185 }
6186
6187 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006188 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006189
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006190 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006191 { MaybeObject* maybe_object =
6192 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006193 if (!maybe_object->ToObject(&object)) return maybe_object;
6194 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006195 SeqAsciiString* answer = SeqAsciiString::cast(object);
6196 StringBuilderConcatHelper(special,
6197 answer->GetChars(),
6198 fixed_array,
6199 array_length);
6200 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006201 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006202 { MaybeObject* maybe_object =
6203 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006204 if (!maybe_object->ToObject(&object)) return maybe_object;
6205 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006206 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6207 StringBuilderConcatHelper(special,
6208 answer->GetChars(),
6209 fixed_array,
6210 array_length);
6211 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006212 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006213}
6214
6215
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006216static MaybeObject* Runtime_StringBuilderJoin(RUNTIME_CALLING_CONVENTION) {
6217 RUNTIME_GET_ISOLATE;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006218 NoHandleAllocation ha;
6219 ASSERT(args.length() == 3);
6220 CONVERT_CHECKED(JSArray, array, args[0]);
6221 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006222 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006223 return Failure::OutOfMemoryException();
6224 }
6225 int array_length = Smi::cast(args[1])->value();
6226 CONVERT_CHECKED(String, separator, args[2]);
6227
6228 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006229 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006230 }
6231 FixedArray* fixed_array = FixedArray::cast(array->elements());
6232 if (fixed_array->length() < array_length) {
6233 array_length = fixed_array->length();
6234 }
6235
6236 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006237 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006238 } else if (array_length == 1) {
6239 Object* first = fixed_array->get(0);
6240 if (first->IsString()) return first;
6241 }
6242
6243 int separator_length = separator->length();
6244 int max_nof_separators =
6245 (String::kMaxLength + separator_length - 1) / separator_length;
6246 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006247 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006248 return Failure::OutOfMemoryException();
6249 }
6250 int length = (array_length - 1) * separator_length;
6251 for (int i = 0; i < array_length; i++) {
6252 Object* element_obj = fixed_array->get(i);
6253 if (!element_obj->IsString()) {
6254 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006255 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006256 }
6257 String* element = String::cast(element_obj);
6258 int increment = element->length();
6259 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006260 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006261 return Failure::OutOfMemoryException();
6262 }
6263 length += increment;
6264 }
6265
6266 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006267 { MaybeObject* maybe_object =
6268 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006269 if (!maybe_object->ToObject(&object)) return maybe_object;
6270 }
6271 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6272
6273 uc16* sink = answer->GetChars();
6274#ifdef DEBUG
6275 uc16* end = sink + length;
6276#endif
6277
6278 String* first = String::cast(fixed_array->get(0));
6279 int first_length = first->length();
6280 String::WriteToFlat(first, sink, 0, first_length);
6281 sink += first_length;
6282
6283 for (int i = 1; i < array_length; i++) {
6284 ASSERT(sink + separator_length <= end);
6285 String::WriteToFlat(separator, sink, 0, separator_length);
6286 sink += separator_length;
6287
6288 String* element = String::cast(fixed_array->get(i));
6289 int element_length = element->length();
6290 ASSERT(sink + element_length <= end);
6291 String::WriteToFlat(element, sink, 0, element_length);
6292 sink += element_length;
6293 }
6294 ASSERT(sink == end);
6295
6296 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6297 return answer;
6298}
6299
6300
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006301static MaybeObject* Runtime_NumberOr(RUNTIME_CALLING_CONVENTION) {
6302 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006303 NoHandleAllocation ha;
6304 ASSERT(args.length() == 2);
6305
6306 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6307 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006308 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006309}
6310
6311
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006312static MaybeObject* Runtime_NumberAnd(RUNTIME_CALLING_CONVENTION) {
6313 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006314 NoHandleAllocation ha;
6315 ASSERT(args.length() == 2);
6316
6317 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6318 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006319 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006320}
6321
6322
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006323static MaybeObject* Runtime_NumberXor(RUNTIME_CALLING_CONVENTION) {
6324 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006325 NoHandleAllocation ha;
6326 ASSERT(args.length() == 2);
6327
6328 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6329 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006330 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006331}
6332
6333
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006334static MaybeObject* Runtime_NumberNot(RUNTIME_CALLING_CONVENTION) {
6335 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006336 NoHandleAllocation ha;
6337 ASSERT(args.length() == 1);
6338
6339 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006340 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006341}
6342
6343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006344static MaybeObject* Runtime_NumberShl(RUNTIME_CALLING_CONVENTION) {
6345 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006346 NoHandleAllocation ha;
6347 ASSERT(args.length() == 2);
6348
6349 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6350 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006351 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006352}
6353
6354
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006355static MaybeObject* Runtime_NumberShr(RUNTIME_CALLING_CONVENTION) {
6356 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006357 NoHandleAllocation ha;
6358 ASSERT(args.length() == 2);
6359
6360 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6361 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006362 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006363}
6364
6365
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006366static MaybeObject* Runtime_NumberSar(RUNTIME_CALLING_CONVENTION) {
6367 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006368 NoHandleAllocation ha;
6369 ASSERT(args.length() == 2);
6370
6371 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6372 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006373 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006374}
6375
6376
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006377static MaybeObject* Runtime_NumberEquals(RUNTIME_CALLING_CONVENTION) {
6378 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006379 NoHandleAllocation ha;
6380 ASSERT(args.length() == 2);
6381
6382 CONVERT_DOUBLE_CHECKED(x, args[0]);
6383 CONVERT_DOUBLE_CHECKED(y, args[1]);
6384 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6385 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6386 if (x == y) return Smi::FromInt(EQUAL);
6387 Object* result;
6388 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6389 result = Smi::FromInt(EQUAL);
6390 } else {
6391 result = Smi::FromInt(NOT_EQUAL);
6392 }
6393 return result;
6394}
6395
6396
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006397static MaybeObject* Runtime_StringEquals(RUNTIME_CALLING_CONVENTION) {
6398 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006399 NoHandleAllocation ha;
6400 ASSERT(args.length() == 2);
6401
6402 CONVERT_CHECKED(String, x, args[0]);
6403 CONVERT_CHECKED(String, y, args[1]);
6404
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006405 bool not_equal = !x->Equals(y);
6406 // This is slightly convoluted because the value that signifies
6407 // equality is 0 and inequality is 1 so we have to negate the result
6408 // from String::Equals.
6409 ASSERT(not_equal == 0 || not_equal == 1);
6410 STATIC_CHECK(EQUAL == 0);
6411 STATIC_CHECK(NOT_EQUAL == 1);
6412 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006413}
6414
6415
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006416static MaybeObject* Runtime_NumberCompare(RUNTIME_CALLING_CONVENTION) {
6417 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006418 NoHandleAllocation ha;
6419 ASSERT(args.length() == 3);
6420
6421 CONVERT_DOUBLE_CHECKED(x, args[0]);
6422 CONVERT_DOUBLE_CHECKED(y, args[1]);
6423 if (isnan(x) || isnan(y)) return args[2];
6424 if (x == y) return Smi::FromInt(EQUAL);
6425 if (isless(x, y)) return Smi::FromInt(LESS);
6426 return Smi::FromInt(GREATER);
6427}
6428
6429
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006430// Compare two Smis as if they were converted to strings and then
6431// compared lexicographically.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006432static MaybeObject* Runtime_SmiLexicographicCompare(
6433 RUNTIME_CALLING_CONVENTION) {
6434 RUNTIME_GET_ISOLATE;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006435 NoHandleAllocation ha;
6436 ASSERT(args.length() == 2);
6437
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006438 // Extract the integer values from the Smis.
6439 CONVERT_CHECKED(Smi, x, args[0]);
6440 CONVERT_CHECKED(Smi, y, args[1]);
6441 int x_value = x->value();
6442 int y_value = y->value();
6443
6444 // If the integers are equal so are the string representations.
6445 if (x_value == y_value) return Smi::FromInt(EQUAL);
6446
6447 // If one of the integers are zero the normal integer order is the
6448 // same as the lexicographic order of the string representations.
6449 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6450
ager@chromium.org32912102009-01-16 10:38:43 +00006451 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006452 // smallest because the char code of '-' is less than the char code
6453 // of any digit. Otherwise, we make both values positive.
6454 if (x_value < 0 || y_value < 0) {
6455 if (y_value >= 0) return Smi::FromInt(LESS);
6456 if (x_value >= 0) return Smi::FromInt(GREATER);
6457 x_value = -x_value;
6458 y_value = -y_value;
6459 }
6460
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006461 // Arrays for the individual characters of the two Smis. Smis are
6462 // 31 bit integers and 10 decimal digits are therefore enough.
6463 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6464 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6465 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6466
6467
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006468 // Convert the integers to arrays of their decimal digits.
6469 int x_index = 0;
6470 int y_index = 0;
6471 while (x_value > 0) {
6472 x_elms[x_index++] = x_value % 10;
6473 x_value /= 10;
6474 }
6475 while (y_value > 0) {
6476 y_elms[y_index++] = y_value % 10;
6477 y_value /= 10;
6478 }
6479
6480 // Loop through the arrays of decimal digits finding the first place
6481 // where they differ.
6482 while (--x_index >= 0 && --y_index >= 0) {
6483 int diff = x_elms[x_index] - y_elms[y_index];
6484 if (diff != 0) return Smi::FromInt(diff);
6485 }
6486
6487 // If one array is a suffix of the other array, the longest array is
6488 // the representation of the largest of the Smis in the
6489 // lexicographic ordering.
6490 return Smi::FromInt(x_index - y_index);
6491}
6492
6493
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006494static Object* StringInputBufferCompare(RuntimeState* state,
6495 String* x,
6496 String* y) {
6497 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6498 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006499 bufx.Reset(x);
6500 bufy.Reset(y);
6501 while (bufx.has_more() && bufy.has_more()) {
6502 int d = bufx.GetNext() - bufy.GetNext();
6503 if (d < 0) return Smi::FromInt(LESS);
6504 else if (d > 0) return Smi::FromInt(GREATER);
6505 }
6506
6507 // x is (non-trivial) prefix of y:
6508 if (bufy.has_more()) return Smi::FromInt(LESS);
6509 // y is prefix of x:
6510 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6511}
6512
6513
6514static Object* FlatStringCompare(String* x, String* y) {
6515 ASSERT(x->IsFlat());
6516 ASSERT(y->IsFlat());
6517 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6518 int prefix_length = x->length();
6519 if (y->length() < prefix_length) {
6520 prefix_length = y->length();
6521 equal_prefix_result = Smi::FromInt(GREATER);
6522 } else if (y->length() > prefix_length) {
6523 equal_prefix_result = Smi::FromInt(LESS);
6524 }
6525 int r;
6526 if (x->IsAsciiRepresentation()) {
6527 Vector<const char> x_chars = x->ToAsciiVector();
6528 if (y->IsAsciiRepresentation()) {
6529 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006530 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006531 } else {
6532 Vector<const uc16> y_chars = y->ToUC16Vector();
6533 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6534 }
6535 } else {
6536 Vector<const uc16> x_chars = x->ToUC16Vector();
6537 if (y->IsAsciiRepresentation()) {
6538 Vector<const char> y_chars = y->ToAsciiVector();
6539 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6540 } else {
6541 Vector<const uc16> y_chars = y->ToUC16Vector();
6542 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6543 }
6544 }
6545 Object* result;
6546 if (r == 0) {
6547 result = equal_prefix_result;
6548 } else {
6549 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6550 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006551 ASSERT(result ==
6552 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006553 return result;
6554}
6555
6556
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006557static MaybeObject* Runtime_StringCompare(RUNTIME_CALLING_CONVENTION) {
6558 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006559 NoHandleAllocation ha;
6560 ASSERT(args.length() == 2);
6561
6562 CONVERT_CHECKED(String, x, args[0]);
6563 CONVERT_CHECKED(String, y, args[1]);
6564
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006565 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006566
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006567 // A few fast case tests before we flatten.
6568 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006569 if (y->length() == 0) {
6570 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006571 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006572 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006573 return Smi::FromInt(LESS);
6574 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006575
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006576 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006577 if (d < 0) return Smi::FromInt(LESS);
6578 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006579
lrn@chromium.org303ada72010-10-27 09:33:13 +00006580 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006581 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006582 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6583 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006584 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006585 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6586 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006588 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006589 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006590}
6591
6592
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006593static MaybeObject* Runtime_Math_acos(RUNTIME_CALLING_CONVENTION) {
6594 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006595 NoHandleAllocation ha;
6596 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006597 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006598
6599 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006600 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006601}
6602
6603
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006604static MaybeObject* Runtime_Math_asin(RUNTIME_CALLING_CONVENTION) {
6605 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006606 NoHandleAllocation ha;
6607 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006608 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006609
6610 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006611 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006612}
6613
6614
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006615static MaybeObject* Runtime_Math_atan(RUNTIME_CALLING_CONVENTION) {
6616 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006617 NoHandleAllocation ha;
6618 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006619 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006620
6621 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006622 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006623}
6624
6625
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006626static const double kPiDividedBy4 = 0.78539816339744830962;
6627
6628
6629static MaybeObject* Runtime_Math_atan2(RUNTIME_CALLING_CONVENTION) {
6630 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006631 NoHandleAllocation ha;
6632 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006633 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006634
6635 CONVERT_DOUBLE_CHECKED(x, args[0]);
6636 CONVERT_DOUBLE_CHECKED(y, args[1]);
6637 double result;
6638 if (isinf(x) && isinf(y)) {
6639 // Make sure that the result in case of two infinite arguments
6640 // is a multiple of Pi / 4. The sign of the result is determined
6641 // by the first argument (x) and the sign of the second argument
6642 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006643 int multiplier = (x < 0) ? -1 : 1;
6644 if (y < 0) multiplier *= 3;
6645 result = multiplier * kPiDividedBy4;
6646 } else {
6647 result = atan2(x, y);
6648 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006649 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006650}
6651
6652
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006653static MaybeObject* Runtime_Math_ceil(RUNTIME_CALLING_CONVENTION) {
6654 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006655 NoHandleAllocation ha;
6656 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006657 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006658
6659 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006660 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006661}
6662
6663
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006664static MaybeObject* Runtime_Math_cos(RUNTIME_CALLING_CONVENTION) {
6665 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006666 NoHandleAllocation ha;
6667 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006668 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006669
6670 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006671 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006672}
6673
6674
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006675static MaybeObject* Runtime_Math_exp(RUNTIME_CALLING_CONVENTION) {
6676 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006677 NoHandleAllocation ha;
6678 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006679 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006680
6681 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006682 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006683}
6684
6685
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006686static MaybeObject* Runtime_Math_floor(RUNTIME_CALLING_CONVENTION) {
6687 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006688 NoHandleAllocation ha;
6689 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006690 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006691
6692 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006693 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006694}
6695
6696
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006697static MaybeObject* Runtime_Math_log(RUNTIME_CALLING_CONVENTION) {
6698 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006699 NoHandleAllocation ha;
6700 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006701 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006702
6703 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006704 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006705}
6706
6707
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006708static MaybeObject* Runtime_Math_pow(RUNTIME_CALLING_CONVENTION) {
6709 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006710 NoHandleAllocation ha;
6711 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006712 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006713
6714 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006715
6716 // If the second argument is a smi, it is much faster to call the
6717 // custom powi() function than the generic pow().
6718 if (args[1]->IsSmi()) {
6719 int y = Smi::cast(args[1])->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006720 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006721 }
6722
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006723 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006724 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006725}
6726
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006727// Fast version of Math.pow if we know that y is not an integer and
6728// y is not -0.5 or 0.5. Used as slowcase from codegen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006729static MaybeObject* Runtime_Math_pow_cfunction(RUNTIME_CALLING_CONVENTION) {
6730 RUNTIME_GET_ISOLATE;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006731 NoHandleAllocation ha;
6732 ASSERT(args.length() == 2);
6733 CONVERT_DOUBLE_CHECKED(x, args[0]);
6734 CONVERT_DOUBLE_CHECKED(y, args[1]);
6735 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006736 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006737 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006738 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006739 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006740 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006741 }
6742}
6743
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006744
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006745static MaybeObject* Runtime_RoundNumber(RUNTIME_CALLING_CONVENTION) {
6746 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006747 NoHandleAllocation ha;
6748 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006749 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006750
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006751 if (!args[0]->IsHeapNumber()) {
6752 // Must be smi. Return the argument unchanged for all the other types
6753 // to make fuzz-natives test happy.
6754 return args[0];
6755 }
6756
6757 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6758
6759 double value = number->value();
6760 int exponent = number->get_exponent();
6761 int sign = number->get_sign();
6762
6763 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6764 // should be rounded to 2^30, which is not smi.
6765 if (!sign && exponent <= kSmiValueSize - 3) {
6766 return Smi::FromInt(static_cast<int>(value + 0.5));
6767 }
6768
6769 // If the magnitude is big enough, there's no place for fraction part. If we
6770 // try to add 0.5 to this number, 1.0 will be added instead.
6771 if (exponent >= 52) {
6772 return number;
6773 }
6774
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006775 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006776
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006777 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006778 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006779}
6780
6781
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006782static MaybeObject* Runtime_Math_sin(RUNTIME_CALLING_CONVENTION) {
6783 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006784 NoHandleAllocation ha;
6785 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006786 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006787
6788 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006789 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006790}
6791
6792
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006793static MaybeObject* Runtime_Math_sqrt(RUNTIME_CALLING_CONVENTION) {
6794 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006795 NoHandleAllocation ha;
6796 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006797 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006798
6799 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006800 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006801}
6802
6803
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006804static MaybeObject* Runtime_Math_tan(RUNTIME_CALLING_CONVENTION) {
6805 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006806 NoHandleAllocation ha;
6807 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006808 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006809
6810 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006811 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006812}
6813
6814
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006815static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006816 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6817 181, 212, 243, 273, 304, 334};
6818 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6819 182, 213, 244, 274, 305, 335};
6820
6821 year += month / 12;
6822 month %= 12;
6823 if (month < 0) {
6824 year--;
6825 month += 12;
6826 }
6827
6828 ASSERT(month >= 0);
6829 ASSERT(month < 12);
6830
6831 // year_delta is an arbitrary number such that:
6832 // a) year_delta = -1 (mod 400)
6833 // b) year + year_delta > 0 for years in the range defined by
6834 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6835 // Jan 1 1970. This is required so that we don't run into integer
6836 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006837 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006838 // operations.
6839 static const int year_delta = 399999;
6840 static const int base_day = 365 * (1970 + year_delta) +
6841 (1970 + year_delta) / 4 -
6842 (1970 + year_delta) / 100 +
6843 (1970 + year_delta) / 400;
6844
6845 int year1 = year + year_delta;
6846 int day_from_year = 365 * year1 +
6847 year1 / 4 -
6848 year1 / 100 +
6849 year1 / 400 -
6850 base_day;
6851
6852 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006853 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006854 }
6855
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006856 return day_from_year + day_from_month_leap[month] + day - 1;
6857}
6858
6859
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006860static MaybeObject* Runtime_DateMakeDay(RUNTIME_CALLING_CONVENTION) {
6861 RUNTIME_GET_ISOLATE;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006862 NoHandleAllocation ha;
6863 ASSERT(args.length() == 3);
6864
6865 CONVERT_SMI_CHECKED(year, args[0]);
6866 CONVERT_SMI_CHECKED(month, args[1]);
6867 CONVERT_SMI_CHECKED(date, args[2]);
6868
6869 return Smi::FromInt(MakeDay(year, month, date));
6870}
6871
6872
6873static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6874static const int kDaysIn4Years = 4 * 365 + 1;
6875static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6876static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6877static const int kDays1970to2000 = 30 * 365 + 7;
6878static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6879 kDays1970to2000;
6880static const int kYearsOffset = 400000;
6881
6882static const char kDayInYear[] = {
6883 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6884 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6885 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6886 22, 23, 24, 25, 26, 27, 28,
6887 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6888 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6889 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6890 22, 23, 24, 25, 26, 27, 28, 29, 30,
6891 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6892 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6893 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6894 22, 23, 24, 25, 26, 27, 28, 29, 30,
6895 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6896 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6897 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6898 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6899 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6900 22, 23, 24, 25, 26, 27, 28, 29, 30,
6901 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6902 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6903 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6904 22, 23, 24, 25, 26, 27, 28, 29, 30,
6905 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6906 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6907
6908 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6909 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6910 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6911 22, 23, 24, 25, 26, 27, 28,
6912 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6913 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6914 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6915 22, 23, 24, 25, 26, 27, 28, 29, 30,
6916 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6917 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6918 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6919 22, 23, 24, 25, 26, 27, 28, 29, 30,
6920 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6921 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6922 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6923 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6924 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6925 22, 23, 24, 25, 26, 27, 28, 29, 30,
6926 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6927 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6928 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6929 22, 23, 24, 25, 26, 27, 28, 29, 30,
6930 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6931 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6932
6933 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6934 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6935 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6936 22, 23, 24, 25, 26, 27, 28, 29,
6937 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6938 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6939 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6940 22, 23, 24, 25, 26, 27, 28, 29, 30,
6941 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6942 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6943 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6944 22, 23, 24, 25, 26, 27, 28, 29, 30,
6945 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6946 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6947 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6948 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6949 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6950 22, 23, 24, 25, 26, 27, 28, 29, 30,
6951 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6952 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6953 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6954 22, 23, 24, 25, 26, 27, 28, 29, 30,
6955 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6956 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6957
6958 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6959 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6960 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6961 22, 23, 24, 25, 26, 27, 28,
6962 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6963 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6964 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6965 22, 23, 24, 25, 26, 27, 28, 29, 30,
6966 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6967 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6968 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6969 22, 23, 24, 25, 26, 27, 28, 29, 30,
6970 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6971 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6972 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6973 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6974 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6975 22, 23, 24, 25, 26, 27, 28, 29, 30,
6976 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6977 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6978 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6979 22, 23, 24, 25, 26, 27, 28, 29, 30,
6980 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6981 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6982
6983static const char kMonthInYear[] = {
6984 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6985 0, 0, 0, 0, 0, 0,
6986 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6987 1, 1, 1,
6988 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6989 2, 2, 2, 2, 2, 2,
6990 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6991 3, 3, 3, 3, 3,
6992 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6993 4, 4, 4, 4, 4, 4,
6994 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6995 5, 5, 5, 5, 5,
6996 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6997 6, 6, 6, 6, 6, 6,
6998 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6999 7, 7, 7, 7, 7, 7,
7000 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7001 8, 8, 8, 8, 8,
7002 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7003 9, 9, 9, 9, 9, 9,
7004 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7005 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7006 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7007 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7008
7009 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7010 0, 0, 0, 0, 0, 0,
7011 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7012 1, 1, 1,
7013 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7014 2, 2, 2, 2, 2, 2,
7015 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7016 3, 3, 3, 3, 3,
7017 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7018 4, 4, 4, 4, 4, 4,
7019 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7020 5, 5, 5, 5, 5,
7021 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7022 6, 6, 6, 6, 6, 6,
7023 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7024 7, 7, 7, 7, 7, 7,
7025 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7026 8, 8, 8, 8, 8,
7027 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7028 9, 9, 9, 9, 9, 9,
7029 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7030 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7031 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7032 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7033
7034 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7035 0, 0, 0, 0, 0, 0,
7036 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7037 1, 1, 1, 1,
7038 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7039 2, 2, 2, 2, 2, 2,
7040 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7041 3, 3, 3, 3, 3,
7042 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7043 4, 4, 4, 4, 4, 4,
7044 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7045 5, 5, 5, 5, 5,
7046 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7047 6, 6, 6, 6, 6, 6,
7048 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7049 7, 7, 7, 7, 7, 7,
7050 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7051 8, 8, 8, 8, 8,
7052 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7053 9, 9, 9, 9, 9, 9,
7054 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7055 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7056 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7057 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7058
7059 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7060 0, 0, 0, 0, 0, 0,
7061 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7062 1, 1, 1,
7063 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7064 2, 2, 2, 2, 2, 2,
7065 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7066 3, 3, 3, 3, 3,
7067 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7068 4, 4, 4, 4, 4, 4,
7069 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7070 5, 5, 5, 5, 5,
7071 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7072 6, 6, 6, 6, 6, 6,
7073 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7074 7, 7, 7, 7, 7, 7,
7075 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7076 8, 8, 8, 8, 8,
7077 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7078 9, 9, 9, 9, 9, 9,
7079 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7080 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7081 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7082 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7083
7084
7085// This function works for dates from 1970 to 2099.
7086static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007087 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007088#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007089 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007090#endif
7091
7092 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7093 date %= kDaysIn4Years;
7094
7095 month = kMonthInYear[date];
7096 day = kDayInYear[date];
7097
7098 ASSERT(MakeDay(year, month, day) == save_date);
7099}
7100
7101
7102static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007103 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007104#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007105 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007106#endif
7107
7108 date += kDaysOffset;
7109 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7110 date %= kDaysIn400Years;
7111
7112 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7113
7114 date--;
7115 int yd1 = date / kDaysIn100Years;
7116 date %= kDaysIn100Years;
7117 year += 100 * yd1;
7118
7119 date++;
7120 int yd2 = date / kDaysIn4Years;
7121 date %= kDaysIn4Years;
7122 year += 4 * yd2;
7123
7124 date--;
7125 int yd3 = date / 365;
7126 date %= 365;
7127 year += yd3;
7128
7129 bool is_leap = (!yd1 || yd2) && !yd3;
7130
7131 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007132 ASSERT(is_leap || (date >= 0));
7133 ASSERT((date < 365) || (is_leap && (date < 366)));
7134 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7135 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7136 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007137
7138 if (is_leap) {
7139 day = kDayInYear[2*365 + 1 + date];
7140 month = kMonthInYear[2*365 + 1 + date];
7141 } else {
7142 day = kDayInYear[date];
7143 month = kMonthInYear[date];
7144 }
7145
7146 ASSERT(MakeDay(year, month, day) == save_date);
7147}
7148
7149
7150static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007151 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007152 if (date >= 0 && date < 32 * kDaysIn4Years) {
7153 DateYMDFromTimeAfter1970(date, year, month, day);
7154 } else {
7155 DateYMDFromTimeSlow(date, year, month, day);
7156 }
7157}
7158
7159
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007160static MaybeObject* Runtime_DateYMDFromTime(RUNTIME_CALLING_CONVENTION) {
7161 RUNTIME_GET_ISOLATE;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007162 NoHandleAllocation ha;
7163 ASSERT(args.length() == 2);
7164
7165 CONVERT_DOUBLE_CHECKED(t, args[0]);
7166 CONVERT_CHECKED(JSArray, res_array, args[1]);
7167
7168 int year, month, day;
7169 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7170
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007171 RUNTIME_ASSERT(res_array->elements()->map() ==
7172 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007173 FixedArray* elms = FixedArray::cast(res_array->elements());
7174 RUNTIME_ASSERT(elms->length() == 3);
7175
7176 elms->set(0, Smi::FromInt(year));
7177 elms->set(1, Smi::FromInt(month));
7178 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007179
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007180 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007181}
7182
7183
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007184static MaybeObject* Runtime_NewArgumentsFast(RUNTIME_CALLING_CONVENTION) {
7185 RUNTIME_GET_ISOLATE;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007186 NoHandleAllocation ha;
7187 ASSERT(args.length() == 3);
7188
7189 JSFunction* callee = JSFunction::cast(args[0]);
7190 Object** parameters = reinterpret_cast<Object**>(args[1]);
7191 const int length = Smi::cast(args[2])->value();
7192
lrn@chromium.org303ada72010-10-27 09:33:13 +00007193 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007194 { MaybeObject* maybe_result =
7195 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007196 if (!maybe_result->ToObject(&result)) return maybe_result;
7197 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007198 // Allocate the elements if needed.
7199 if (length > 0) {
7200 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007201 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007202 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007203 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7204 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007205
7206 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007207 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007208 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007209 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007210
7211 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007212 for (int i = 0; i < length; i++) {
7213 array->set(i, *--parameters, mode);
7214 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007215 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007216 }
7217 return result;
7218}
7219
7220
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007221static MaybeObject* Runtime_NewClosure(RUNTIME_CALLING_CONVENTION) {
7222 RUNTIME_GET_ISOLATE;
7223 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007224 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007225 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007226 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007227 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007228
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007229 // Allocate global closures in old space and allocate local closures
7230 // in new space. Additionally pretenure closures that are assigned
7231 // directly to properties.
7232 pretenure = pretenure || (context->global_context() == *context);
7233 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007234 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007235 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7236 context,
7237 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007238 return *result;
7239}
7240
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007241static MaybeObject* Runtime_NewObjectFromBound(RUNTIME_CALLING_CONVENTION) {
7242 RUNTIME_GET_ISOLATE;
7243 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007244 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007245 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007246 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007247
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007248 // Second argument is either null or an array of bound arguments.
7249 FixedArray* bound_args = NULL;
7250 int bound_argc = 0;
7251 if (!args[1]->IsNull()) {
7252 CONVERT_ARG_CHECKED(JSArray, params, 1);
7253 RUNTIME_ASSERT(params->HasFastElements());
7254 bound_args = FixedArray::cast(params->elements());
7255 bound_argc = Smi::cast(params->length())->value();
7256 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007257
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007258 // Find frame containing arguments passed to the caller.
7259 JavaScriptFrameIterator it;
7260 JavaScriptFrame* frame = it.frame();
7261 ASSERT(!frame->is_optimized());
7262 it.AdvanceToArgumentsFrame();
7263 frame = it.frame();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007264 int argc = frame->ComputeParametersCount();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007265
7266 // Prepend bound arguments to caller's arguments.
7267 int total_argc = bound_argc + argc;
7268 SmartPointer<Object**> param_data(NewArray<Object**>(total_argc));
7269 for (int i = 0; i < bound_argc; i++) {
7270 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007271 param_data[i] = val.location();
7272 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007273 for (int i = 0; i < argc; i++) {
7274 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7275 param_data[bound_argc + i] = val.location();
7276 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007277
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007278 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007279 Handle<Object> result =
7280 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007281 if (exception) {
7282 return Failure::Exception();
7283 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007284
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007285 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007286 return *result;
7287}
7288
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007289
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007290static void TrySettingInlineConstructStub(Isolate* isolate,
7291 Handle<JSFunction> function) {
7292 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007293 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007294 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007295 }
7296 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007297 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007298 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007299 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007300 function->shared()->set_construct_stub(
7301 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007302 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007303 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007304}
7305
7306
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007307static MaybeObject* Runtime_NewObject(RUNTIME_CALLING_CONVENTION) {
7308 RUNTIME_GET_ISOLATE;
7309 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007310 ASSERT(args.length() == 1);
7311
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007312 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007313
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007314 // If the constructor isn't a proper function we throw a type error.
7315 if (!constructor->IsJSFunction()) {
7316 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7317 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007318 isolate->factory()->NewTypeError("not_constructor", arguments);
7319 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007320 }
7321
7322 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007323
7324 // If function should not have prototype, construction is not allowed. In this
7325 // case generated code bailouts here, since function has no initial_map.
7326 if (!function->should_have_prototype()) {
7327 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7328 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007329 isolate->factory()->NewTypeError("not_constructor", arguments);
7330 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007331 }
7332
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007333#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007334 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007335 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007336 if (debug->StepInActive()) {
7337 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007338 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007339#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007340
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007341 if (function->has_initial_map()) {
7342 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007343 // The 'Function' function ignores the receiver object when
7344 // called using 'new' and creates a new JSFunction object that
7345 // is returned. The receiver object is only used for error
7346 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007347 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007348 // allocate JSFunctions since it does not properly initialize
7349 // the shared part of the function. Since the receiver is
7350 // ignored anyway, we use the global object as the receiver
7351 // instead of a new JSFunction object. This way, errors are
7352 // reported the same way whether or not 'Function' is called
7353 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007354 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007355 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007356 }
7357
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007358 // The function should be compiled for the optimization hints to be
7359 // available. We cannot use EnsureCompiled because that forces a
7360 // compilation through the shared function info which makes it
7361 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007362 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007363 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007364
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007365 if (!function->has_initial_map() &&
7366 shared->IsInobjectSlackTrackingInProgress()) {
7367 // The tracking is already in progress for another function. We can only
7368 // track one initial_map at a time, so we force the completion before the
7369 // function is called as a constructor for the first time.
7370 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007371 }
7372
7373 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007374 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7375 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007376 // Delay setting the stub if inobject slack tracking is in progress.
7377 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007378 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007379 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007380
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007381 isolate->counters()->constructed_objects()->Increment();
7382 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007383
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007384 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007385}
7386
7387
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007388static MaybeObject* Runtime_FinalizeInstanceSize(RUNTIME_CALLING_CONVENTION) {
7389 RUNTIME_GET_ISOLATE;
7390 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007391 ASSERT(args.length() == 1);
7392
7393 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7394 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007395 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007396
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007397 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007398}
7399
7400
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007401static MaybeObject* Runtime_LazyCompile(RUNTIME_CALLING_CONVENTION) {
7402 RUNTIME_GET_ISOLATE;
7403 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007404 ASSERT(args.length() == 1);
7405
7406 Handle<JSFunction> function = args.at<JSFunction>(0);
7407#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007408 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007409 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007410 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007411 PrintF("]\n");
7412 }
7413#endif
7414
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007415 // Compile the target function. Here we compile using CompileLazyInLoop in
7416 // order to get the optimized version. This helps code like delta-blue
7417 // that calls performance-critical routines through constructors. A
7418 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7419 // direct call. Since the in-loop tracking takes place through CallICs
7420 // this means that things called through constructors are never known to
7421 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007422 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007423 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007424 return Failure::Exception();
7425 }
7426
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007427 // All done. Return the compiled code.
7428 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007429 return function->code();
7430}
7431
7432
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007433static MaybeObject* Runtime_LazyRecompile(RUNTIME_CALLING_CONVENTION) {
7434 RUNTIME_GET_ISOLATE;
7435 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007436 ASSERT(args.length() == 1);
7437 Handle<JSFunction> function = args.at<JSFunction>(0);
7438 // If the function is not optimizable or debugger is active continue using the
7439 // code from the full compiler.
7440 if (!function->shared()->code()->optimizable() ||
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007441 isolate->debug()->has_break_points()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007442 if (FLAG_trace_opt) {
7443 PrintF("[failed to optimize ");
7444 function->PrintName();
7445 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7446 function->shared()->code()->optimizable() ? "T" : "F",
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007447 isolate->debug()->has_break_points() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007448 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007449 function->ReplaceCode(function->shared()->code());
7450 return function->code();
7451 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007452 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007453 return function->code();
7454 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007455 if (FLAG_trace_opt) {
7456 PrintF("[failed to optimize ");
7457 function->PrintName();
7458 PrintF(": optimized compilation failed]\n");
7459 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007460 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007461 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007462}
7463
7464
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007465static MaybeObject* Runtime_NotifyDeoptimized(RUNTIME_CALLING_CONVENTION) {
7466 RUNTIME_GET_ISOLATE;
7467 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007468 ASSERT(args.length() == 1);
7469 RUNTIME_ASSERT(args[0]->IsSmi());
7470 Deoptimizer::BailoutType type =
7471 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007472 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7473 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007474 int frames = deoptimizer->output_count();
7475
7476 JavaScriptFrameIterator it;
7477 JavaScriptFrame* frame = NULL;
7478 for (int i = 0; i < frames; i++) {
7479 if (i != 0) it.Advance();
7480 frame = it.frame();
7481 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
7482 }
7483 delete deoptimizer;
7484
7485 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007486 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007487 Handle<Object> arguments;
7488 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007489 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007490 if (arguments.is_null()) {
7491 // FunctionGetArguments can't throw an exception, so cast away the
7492 // doubt with an assert.
7493 arguments = Handle<Object>(
7494 Accessors::FunctionGetArguments(*function,
7495 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007496 ASSERT(*arguments != isolate->heap()->null_value());
7497 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007498 }
7499 frame->SetExpression(i, *arguments);
7500 }
7501 }
7502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007503 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007504 if (type == Deoptimizer::EAGER) {
7505 RUNTIME_ASSERT(function->IsOptimized());
7506 } else {
7507 RUNTIME_ASSERT(!function->IsOptimized());
7508 }
7509
7510 // Avoid doing too much work when running with --always-opt and keep
7511 // the optimized code around.
7512 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007513 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007514 }
7515
7516 // Count the number of optimized activations of the function.
7517 int activations = 0;
7518 while (!it.done()) {
7519 JavaScriptFrame* frame = it.frame();
7520 if (frame->is_optimized() && frame->function() == *function) {
7521 activations++;
7522 }
7523 it.Advance();
7524 }
7525
7526 // TODO(kasperl): For now, we cannot support removing the optimized
7527 // code when we have recursive invocations of the same function.
7528 if (activations == 0) {
7529 if (FLAG_trace_deopt) {
7530 PrintF("[removing optimized code for: ");
7531 function->PrintName();
7532 PrintF("]\n");
7533 }
7534 function->ReplaceCode(function->shared()->code());
7535 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007536 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007537}
7538
7539
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007540static MaybeObject* Runtime_NotifyOSR(RUNTIME_CALLING_CONVENTION) {
7541 RUNTIME_GET_ISOLATE;
7542 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007543 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007544 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007545}
7546
7547
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007548static MaybeObject* Runtime_DeoptimizeFunction(RUNTIME_CALLING_CONVENTION) {
7549 RUNTIME_GET_ISOLATE;
7550 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007551 ASSERT(args.length() == 1);
7552 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007553 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007554
7555 Deoptimizer::DeoptimizeFunction(*function);
7556
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007557 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007558}
7559
7560
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007561static MaybeObject* Runtime_CompileForOnStackReplacement(
7562 RUNTIME_CALLING_CONVENTION) {
7563 RUNTIME_GET_ISOLATE;
7564 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007565 ASSERT(args.length() == 1);
7566 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7567
7568 // We're not prepared to handle a function with arguments object.
7569 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7570
7571 // We have hit a back edge in an unoptimized frame for a function that was
7572 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007573 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007574 // Keep track of whether we've succeeded in optimizing.
7575 bool succeeded = unoptimized->optimizable();
7576 if (succeeded) {
7577 // If we are trying to do OSR when there are already optimized
7578 // activations of the function, it means (a) the function is directly or
7579 // indirectly recursive and (b) an optimized invocation has been
7580 // deoptimized so that we are currently in an unoptimized activation.
7581 // Check for optimized activations of this function.
7582 JavaScriptFrameIterator it;
7583 while (succeeded && !it.done()) {
7584 JavaScriptFrame* frame = it.frame();
7585 succeeded = !frame->is_optimized() || frame->function() != *function;
7586 it.Advance();
7587 }
7588 }
7589
7590 int ast_id = AstNode::kNoNumber;
7591 if (succeeded) {
7592 // The top JS function is this one, the PC is somewhere in the
7593 // unoptimized code.
7594 JavaScriptFrameIterator it;
7595 JavaScriptFrame* frame = it.frame();
7596 ASSERT(frame->function() == *function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007597 ASSERT(frame->LookupCode(isolate) == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007598 ASSERT(unoptimized->contains(frame->pc()));
7599
7600 // Use linear search of the unoptimized code's stack check table to find
7601 // the AST id matching the PC.
7602 Address start = unoptimized->instruction_start();
7603 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007604 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007605 uint32_t table_length = Memory::uint32_at(table_cursor);
7606 table_cursor += kIntSize;
7607 for (unsigned i = 0; i < table_length; ++i) {
7608 // Table entries are (AST id, pc offset) pairs.
7609 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7610 if (pc_offset == target_pc_offset) {
7611 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7612 break;
7613 }
7614 table_cursor += 2 * kIntSize;
7615 }
7616 ASSERT(ast_id != AstNode::kNoNumber);
7617 if (FLAG_trace_osr) {
7618 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7619 function->PrintName();
7620 PrintF("]\n");
7621 }
7622
7623 // Try to compile the optimized code. A true return value from
7624 // CompileOptimized means that compilation succeeded, not necessarily
7625 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007626 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7627 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007628 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7629 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007630 if (data->OsrPcOffset()->value() >= 0) {
7631 if (FLAG_trace_osr) {
7632 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007633 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007634 }
7635 ASSERT(data->OsrAstId()->value() == ast_id);
7636 } else {
7637 // We may never generate the desired OSR entry if we emit an
7638 // early deoptimize.
7639 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007640 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007641 } else {
7642 succeeded = false;
7643 }
7644 }
7645
7646 // Revert to the original stack checks in the original unoptimized code.
7647 if (FLAG_trace_osr) {
7648 PrintF("[restoring original stack checks in ");
7649 function->PrintName();
7650 PrintF("]\n");
7651 }
7652 StackCheckStub check_stub;
7653 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007654 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007655 Deoptimizer::RevertStackCheckCode(*unoptimized,
7656 *check_code,
7657 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007658
7659 // Allow OSR only at nesting level zero again.
7660 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7661
7662 // If the optimization attempt succeeded, return the AST id tagged as a
7663 // smi. This tells the builtin that we need to translate the unoptimized
7664 // frame to an optimized one.
7665 if (succeeded) {
7666 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7667 return Smi::FromInt(ast_id);
7668 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007669 if (function->IsMarkedForLazyRecompilation()) {
7670 function->ReplaceCode(function->shared()->code());
7671 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007672 return Smi::FromInt(-1);
7673 }
7674}
7675
7676
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007677static MaybeObject* Runtime_GetFunctionDelegate(RUNTIME_CALLING_CONVENTION) {
7678 RUNTIME_GET_ISOLATE;
7679 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007680 ASSERT(args.length() == 1);
7681 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7682 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7683}
7684
7685
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007686static MaybeObject* Runtime_GetConstructorDelegate(RUNTIME_CALLING_CONVENTION) {
7687 RUNTIME_GET_ISOLATE;
7688 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007689 ASSERT(args.length() == 1);
7690 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7691 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7692}
7693
7694
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007695static MaybeObject* Runtime_NewContext(RUNTIME_CALLING_CONVENTION) {
7696 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007697 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007698 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007699
kasper.lund7276f142008-07-30 08:49:36 +00007700 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007701 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007702 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007703 { MaybeObject* maybe_result =
7704 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007705 if (!maybe_result->ToObject(&result)) return maybe_result;
7706 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007707
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007708 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007709
kasper.lund7276f142008-07-30 08:49:36 +00007710 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007711}
7712
lrn@chromium.org303ada72010-10-27 09:33:13 +00007713
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007714MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7715 Object* object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007716 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007717 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007718 Object* js_object = object;
7719 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007720 MaybeObject* maybe_js_object = js_object->ToObject();
7721 if (!maybe_js_object->ToObject(&js_object)) {
7722 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7723 return maybe_js_object;
7724 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007725 HandleScope scope(isolate);
7726 Handle<Object> handle(object, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007727 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007728 isolate->factory()->NewTypeError("with_expression",
7729 HandleVector(&handle, 1));
7730 return isolate->Throw(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007731 }
7732 }
7733
lrn@chromium.org303ada72010-10-27 09:33:13 +00007734 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007735 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7736 isolate->context(), JSObject::cast(js_object), is_catch_context);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007737 if (!maybe_result->ToObject(&result)) return maybe_result;
7738 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007739
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007740 Context* context = Context::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007741 isolate->set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007742
kasper.lund7276f142008-07-30 08:49:36 +00007743 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007744}
7745
7746
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007747static MaybeObject* Runtime_PushContext(RUNTIME_CALLING_CONVENTION) {
7748 RUNTIME_GET_ISOLATE;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007749 NoHandleAllocation ha;
7750 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007751 return PushContextHelper(isolate, args[0], false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007752}
7753
7754
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007755static MaybeObject* Runtime_PushCatchContext(RUNTIME_CALLING_CONVENTION) {
7756 RUNTIME_GET_ISOLATE;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007757 NoHandleAllocation ha;
7758 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007759 return PushContextHelper(isolate, args[0], true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007760}
7761
7762
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007763static MaybeObject* Runtime_DeleteContextSlot(RUNTIME_CALLING_CONVENTION) {
7764 RUNTIME_GET_ISOLATE;
7765 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007766 ASSERT(args.length() == 2);
7767
7768 CONVERT_ARG_CHECKED(Context, context, 0);
7769 CONVERT_ARG_CHECKED(String, name, 1);
7770
7771 int index;
7772 PropertyAttributes attributes;
7773 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007774 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007775
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007776 // If the slot was not found the result is true.
7777 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007778 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007779 }
7780
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007781 // If the slot was found in a context, it should be DONT_DELETE.
7782 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007783 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007784 }
7785
7786 // The slot was found in a JSObject, either a context extension object,
7787 // the global object, or an arguments object. Try to delete it
7788 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7789 // which allows deleting all parameters in functions that mention
7790 // 'arguments', we do this even for the case of slots found on an
7791 // arguments object. The slot was found on an arguments object if the
7792 // index is non-negative.
7793 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7794 if (index >= 0) {
7795 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7796 } else {
7797 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7798 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007799}
7800
7801
ager@chromium.orga1645e22009-09-09 19:27:10 +00007802// A mechanism to return a pair of Object pointers in registers (if possible).
7803// How this is achieved is calling convention-dependent.
7804// All currently supported x86 compiles uses calling conventions that are cdecl
7805// variants where a 64-bit value is returned in two 32-bit registers
7806// (edx:eax on ia32, r1:r0 on ARM).
7807// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7808// In Win64 calling convention, a struct of two pointers is returned in memory,
7809// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007810#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007811struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007812 MaybeObject* x;
7813 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007814};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007815
lrn@chromium.org303ada72010-10-27 09:33:13 +00007816static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007817 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007818 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7819 // In Win64 they are assigned to a hidden first argument.
7820 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007821}
7822#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007823typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007824static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007825 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007826 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007827}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007828#endif
7829
7830
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007831static inline MaybeObject* Unhole(Heap* heap,
7832 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007833 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007834 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7835 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007836 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007837}
7838
7839
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007840static JSObject* ComputeReceiverForNonGlobal(Isolate* isolate,
7841 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007842 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007843 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007844 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007845 JSFunction* context_extension_function =
7846 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007847 // If the holder isn't a context extension object, we just return it
7848 // as the receiver. This allows arguments objects to be used as
7849 // receivers, but only if they are put in the context scope chain
7850 // explicitly via a with-statement.
7851 Object* constructor = holder->map()->constructor();
7852 if (constructor != context_extension_function) return holder;
7853 // Fall back to using the global object as the receiver if the
7854 // property turns out to be a local variable allocated in a context
7855 // extension object - introduced via eval.
7856 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007857}
7858
7859
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007860static ObjectPair LoadContextSlotHelper(Arguments args,
7861 Isolate* isolate,
7862 bool throw_error) {
7863 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00007864 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007865
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007866 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007867 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007868 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007869 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007870 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007871
7872 int index;
7873 PropertyAttributes attributes;
7874 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007875 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007876
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007877 // If the index is non-negative, the slot has been found in a local
7878 // variable or a parameter. Read it from the context object or the
7879 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007880 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007881 // If the "property" we were looking for is a local variable or an
7882 // argument in a context, the receiver is the global object; see
7883 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007884 JSObject* receiver =
7885 isolate->context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007886 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007887 ? Context::cast(*holder)->get(index)
7888 : JSObject::cast(*holder)->GetElement(index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007889 return MakePair(Unhole(isolate->heap(), value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007890 }
7891
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007892 // If the holder is found, we read the property from it.
7893 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007894 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007895 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007896 JSObject* receiver;
7897 if (object->IsGlobalObject()) {
7898 receiver = GlobalObject::cast(object)->global_receiver();
7899 } else if (context->is_exception_holder(*holder)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007900 receiver = isolate->context()->global()->global_receiver();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007901 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007902 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007903 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007904 // No need to unhole the value here. This is taken care of by the
7905 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007906 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007907 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007908 }
7909
7910 if (throw_error) {
7911 // The property doesn't exist - throw exception.
7912 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007913 isolate->factory()->NewReferenceError("not_defined",
7914 HandleVector(&name, 1));
7915 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007916 } else {
7917 // The property doesn't exist - return undefined
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007918 return MakePair(isolate->heap()->undefined_value(),
7919 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007920 }
7921}
7922
7923
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007924static ObjectPair Runtime_LoadContextSlot(RUNTIME_CALLING_CONVENTION) {
7925 RUNTIME_GET_ISOLATE;
7926 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007927}
7928
7929
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007930static ObjectPair Runtime_LoadContextSlotNoReferenceError(
7931 RUNTIME_CALLING_CONVENTION) {
7932 RUNTIME_GET_ISOLATE;
7933 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007934}
7935
7936
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007937static MaybeObject* Runtime_StoreContextSlot(RUNTIME_CALLING_CONVENTION) {
7938 RUNTIME_GET_ISOLATE;
7939 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007940 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007941
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007942 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007943 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007944 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007945 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
7946 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
7947 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007948 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007949
7950 int index;
7951 PropertyAttributes attributes;
7952 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007953 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007954
7955 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007956 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007957 // Ignore if read_only variable.
7958 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007959 // Context is a fixed array and set cannot fail.
7960 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007961 } else if (strict_mode == kStrictMode) {
7962 // Setting read only property in strict mode.
7963 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007964 isolate->factory()->NewTypeError("strict_cannot_assign",
7965 HandleVector(&name, 1));
7966 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007967 }
7968 } else {
7969 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007970 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007971 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007972 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007973 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007974 return Failure::Exception();
7975 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007976 }
7977 return *value;
7978 }
7979
7980 // Slow case: The property is not in a FixedArray context.
7981 // It is either in an JSObject extension context or it was not found.
7982 Handle<JSObject> context_ext;
7983
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007984 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007985 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007986 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007987 } else {
7988 // The property was not found. It needs to be stored in the global context.
7989 ASSERT(attributes == ABSENT);
7990 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007991 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007992 }
7993
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007994 // Set the property, but ignore if read_only variable on the context
7995 // extension object itself.
7996 if ((attributes & READ_ONLY) == 0 ||
7997 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007998 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007999 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008000 SetProperty(context_ext, name, value, NONE, strict_mode));
8001 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008002 // Setting read only property in strict mode.
8003 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008004 isolate->factory()->NewTypeError(
8005 "strict_cannot_assign", HandleVector(&name, 1));
8006 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008007 }
8008 return *value;
8009}
8010
8011
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008012static MaybeObject* Runtime_Throw(RUNTIME_CALLING_CONVENTION) {
8013 RUNTIME_GET_ISOLATE;
8014 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008015 ASSERT(args.length() == 1);
8016
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008017 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008018}
8019
8020
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008021static MaybeObject* Runtime_ReThrow(RUNTIME_CALLING_CONVENTION) {
8022 RUNTIME_GET_ISOLATE;
8023 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008024 ASSERT(args.length() == 1);
8025
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008026 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008027}
8028
8029
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008030static MaybeObject* Runtime_PromoteScheduledException(
8031 RUNTIME_CALLING_CONVENTION) {
8032 RUNTIME_GET_ISOLATE;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008033 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008034 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008035}
8036
8037
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008038static MaybeObject* Runtime_ThrowReferenceError(RUNTIME_CALLING_CONVENTION) {
8039 RUNTIME_GET_ISOLATE;
8040 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008041 ASSERT(args.length() == 1);
8042
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008043 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008044 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008045 isolate->factory()->NewReferenceError("not_defined",
8046 HandleVector(&name, 1));
8047 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008048}
8049
8050
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008051static MaybeObject* Runtime_StackGuard(RUNTIME_CALLING_CONVENTION) {
8052 RUNTIME_GET_ISOLATE;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008053 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008054
8055 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008056 if (isolate->stack_guard()->IsStackOverflow()) {
8057 NoHandleAllocation na;
8058 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008059 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008060
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008061 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008062}
8063
8064
8065// NOTE: These PrintXXX functions are defined for all builds (not just
8066// DEBUG builds) because we may want to be able to trace function
8067// calls in all modes.
8068static void PrintString(String* str) {
8069 // not uncommon to have empty strings
8070 if (str->length() > 0) {
8071 SmartPointer<char> s =
8072 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8073 PrintF("%s", *s);
8074 }
8075}
8076
8077
8078static void PrintObject(Object* obj) {
8079 if (obj->IsSmi()) {
8080 PrintF("%d", Smi::cast(obj)->value());
8081 } else if (obj->IsString() || obj->IsSymbol()) {
8082 PrintString(String::cast(obj));
8083 } else if (obj->IsNumber()) {
8084 PrintF("%g", obj->Number());
8085 } else if (obj->IsFailure()) {
8086 PrintF("<failure>");
8087 } else if (obj->IsUndefined()) {
8088 PrintF("<undefined>");
8089 } else if (obj->IsNull()) {
8090 PrintF("<null>");
8091 } else if (obj->IsTrue()) {
8092 PrintF("<true>");
8093 } else if (obj->IsFalse()) {
8094 PrintF("<false>");
8095 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008096 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008097 }
8098}
8099
8100
8101static int StackSize() {
8102 int n = 0;
8103 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8104 return n;
8105}
8106
8107
8108static void PrintTransition(Object* result) {
8109 // indentation
8110 { const int nmax = 80;
8111 int n = StackSize();
8112 if (n <= nmax)
8113 PrintF("%4d:%*s", n, n, "");
8114 else
8115 PrintF("%4d:%*s", n, nmax, "...");
8116 }
8117
8118 if (result == NULL) {
8119 // constructor calls
8120 JavaScriptFrameIterator it;
8121 JavaScriptFrame* frame = it.frame();
8122 if (frame->IsConstructor()) PrintF("new ");
8123 // function name
8124 Object* fun = frame->function();
8125 if (fun->IsJSFunction()) {
8126 PrintObject(JSFunction::cast(fun)->shared()->name());
8127 } else {
8128 PrintObject(fun);
8129 }
8130 // function arguments
8131 // (we are intentionally only printing the actually
8132 // supplied parameters, not all parameters required)
8133 PrintF("(this=");
8134 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008135 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008136 for (int i = 0; i < length; i++) {
8137 PrintF(", ");
8138 PrintObject(frame->GetParameter(i));
8139 }
8140 PrintF(") {\n");
8141
8142 } else {
8143 // function result
8144 PrintF("} -> ");
8145 PrintObject(result);
8146 PrintF("\n");
8147 }
8148}
8149
8150
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008151static MaybeObject* Runtime_TraceEnter(RUNTIME_CALLING_CONVENTION) {
8152 RUNTIME_GET_ISOLATE;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008153 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008154 NoHandleAllocation ha;
8155 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008156 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008157}
8158
8159
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008160static MaybeObject* Runtime_TraceExit(RUNTIME_CALLING_CONVENTION) {
8161 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008162 NoHandleAllocation ha;
8163 PrintTransition(args[0]);
8164 return args[0]; // return TOS
8165}
8166
8167
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008168static MaybeObject* Runtime_DebugPrint(RUNTIME_CALLING_CONVENTION) {
8169 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008170 NoHandleAllocation ha;
8171 ASSERT(args.length() == 1);
8172
8173#ifdef DEBUG
8174 if (args[0]->IsString()) {
8175 // If we have a string, assume it's a code "marker"
8176 // and print some interesting cpu debugging info.
8177 JavaScriptFrameIterator it;
8178 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008179 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8180 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008181 } else {
8182 PrintF("DebugPrint: ");
8183 }
8184 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008185 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008186 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008187 HeapObject::cast(args[0])->map()->Print();
8188 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008189#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008190 // ShortPrint is available in release mode. Print is not.
8191 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008192#endif
8193 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008194 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008195
8196 return args[0]; // return TOS
8197}
8198
8199
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008200static MaybeObject* Runtime_DebugTrace(RUNTIME_CALLING_CONVENTION) {
8201 RUNTIME_GET_ISOLATE;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008202 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008203 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008204 isolate->PrintStack();
8205 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008206}
8207
8208
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008209static MaybeObject* Runtime_DateCurrentTime(RUNTIME_CALLING_CONVENTION) {
8210 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008211 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008212 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008213
8214 // According to ECMA-262, section 15.9.1, page 117, the precision of
8215 // the number in a Date object representing a particular instant in
8216 // time is milliseconds. Therefore, we floor the result of getting
8217 // the OS time.
8218 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008219 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008220}
8221
8222
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008223static MaybeObject* Runtime_DateParseString(RUNTIME_CALLING_CONVENTION) {
8224 RUNTIME_GET_ISOLATE;
8225 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008226 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008227
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008228 CONVERT_ARG_CHECKED(String, str, 0);
8229 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008230
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008231 CONVERT_ARG_CHECKED(JSArray, output, 1);
8232 RUNTIME_ASSERT(output->HasFastElements());
8233
8234 AssertNoAllocation no_allocation;
8235
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008236 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008237 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8238 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008239 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008240 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008241 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008242 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008243 result = DateParser::Parse(str->ToUC16Vector(), output_array);
8244 }
8245
8246 if (result) {
8247 return *output;
8248 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008249 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008250 }
8251}
8252
8253
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008254static MaybeObject* Runtime_DateLocalTimezone(RUNTIME_CALLING_CONVENTION) {
8255 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008256 NoHandleAllocation ha;
8257 ASSERT(args.length() == 1);
8258
8259 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008260 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008261 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008262}
8263
8264
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008265static MaybeObject* Runtime_DateLocalTimeOffset(RUNTIME_CALLING_CONVENTION) {
8266 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008267 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008268 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008269
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008270 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008271}
8272
8273
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008274static MaybeObject* Runtime_DateDaylightSavingsOffset(
8275 RUNTIME_CALLING_CONVENTION) {
8276 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008277 NoHandleAllocation ha;
8278 ASSERT(args.length() == 1);
8279
8280 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008281 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008282}
8283
8284
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008285static MaybeObject* Runtime_GlobalReceiver(RUNTIME_CALLING_CONVENTION) {
8286 RUNTIME_GET_ISOLATE;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008287 ASSERT(args.length() == 1);
8288 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008289 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008290 return JSGlobalObject::cast(global)->global_receiver();
8291}
8292
8293
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008294static MaybeObject* Runtime_ParseJson(RUNTIME_CALLING_CONVENTION) {
8295 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008296 ASSERT_EQ(1, args.length());
8297 CONVERT_ARG_CHECKED(String, source, 0);
8298
8299 Handle<Object> result = JsonParser::Parse(source);
8300 if (result.is_null()) {
8301 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008302 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008303 return Failure::Exception();
8304 }
8305 return *result;
8306}
8307
8308
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008309static MaybeObject* Runtime_CompileString(RUNTIME_CALLING_CONVENTION) {
8310 RUNTIME_GET_ISOLATE;
8311 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008312 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008313 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008314
ager@chromium.org381abbb2009-02-25 13:23:22 +00008315 // Compile source string in the global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008316 Handle<Context> context(isolate->context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008317 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8318 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008319 true,
8320 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008321 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008322 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008323 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8324 context,
8325 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008326 return *fun;
8327}
8328
8329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008330static ObjectPair CompileGlobalEval(Isolate* isolate,
8331 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008332 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008333 StrictModeFlag strict_mode) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008334 // Deal with a normal eval call with a string argument. Compile it
8335 // and return the compiled function bound in the local context.
8336 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8337 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008338 Handle<Context>(isolate->context()),
8339 isolate->context()->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008340 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008341 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008342 Handle<JSFunction> compiled =
8343 isolate->factory()->NewFunctionFromSharedFunctionInfo(
8344 shared, Handle<Context>(isolate->context()), NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008345 return MakePair(*compiled, *receiver);
8346}
8347
8348
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008349static ObjectPair Runtime_ResolvePossiblyDirectEval(
8350 RUNTIME_CALLING_CONVENTION) {
8351 RUNTIME_GET_ISOLATE;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008352 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008353
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008354 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008355 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008356 Handle<Object> receiver; // Will be overwritten.
8357
8358 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008359 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008360#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008361 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008362 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008363 StackFrameLocator locator;
8364 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008365 ASSERT(Context::cast(frame->context()) == *context);
8366#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008367
8368 // Find where the 'eval' symbol is bound. It is unaliased only if
8369 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008370 int index = -1;
8371 PropertyAttributes attributes = ABSENT;
8372 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008373 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8374 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008375 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008376 // Stop search when eval is found or when the global context is
8377 // reached.
8378 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008379 if (context->is_function_context()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008380 context = Handle<Context>(Context::cast(context->closure()->context()),
8381 isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008382 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008383 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008384 }
8385 }
8386
iposva@chromium.org245aa852009-02-10 00:49:54 +00008387 // If eval could not be resolved, it has been deleted and we need to
8388 // throw a reference error.
8389 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008390 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008391 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008392 isolate->factory()->NewReferenceError("not_defined",
8393 HandleVector(&name, 1));
8394 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008395 }
8396
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008397 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008398 // 'eval' is not bound in the global context. Just call the function
8399 // with the given arguments. This is not necessarily the global eval.
8400 if (receiver->IsContext()) {
8401 context = Handle<Context>::cast(receiver);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008402 receiver = Handle<Object>(context->get(index), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008403 } else if (receiver->IsJSContextExtensionObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008404 receiver = Handle<JSObject>(
8405 isolate->context()->global()->global_receiver(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008406 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008407 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008408 }
8409
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008410 // 'eval' is bound in the global context, but it may have been overwritten.
8411 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008412 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008413 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008414 return MakePair(*callee,
8415 isolate->context()->global()->global_receiver());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008416 }
8417
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008418 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008419 return CompileGlobalEval(isolate,
8420 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008421 args.at<Object>(2),
8422 static_cast<StrictModeFlag>(
8423 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008424}
8425
8426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008427static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(
8428 RUNTIME_CALLING_CONVENTION) {
8429 RUNTIME_GET_ISOLATE;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008430 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008431
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008432 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008433 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008434
8435 // 'eval' is bound in the global context, but it may have been overwritten.
8436 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008437 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008438 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008439 return MakePair(*callee,
8440 isolate->context()->global()->global_receiver());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008441 }
8442
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008443 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008444 return CompileGlobalEval(isolate,
8445 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008446 args.at<Object>(2),
8447 static_cast<StrictModeFlag>(
8448 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008449}
8450
8451
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008452static MaybeObject* Runtime_SetNewFunctionAttributes(
8453 RUNTIME_CALLING_CONVENTION) {
8454 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008455 // This utility adjusts the property attributes for newly created Function
8456 // object ("new Function(...)") by changing the map.
8457 // All it does is changing the prototype property to enumerable
8458 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008459 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008460 ASSERT(args.length() == 1);
8461 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008462
8463 Handle<Map> map = func->shared()->strict_mode()
8464 ? isolate->strict_mode_function_instance_map()
8465 : isolate->function_instance_map();
8466
8467 ASSERT(func->map()->instance_type() == map->instance_type());
8468 ASSERT(func->map()->instance_size() == map->instance_size());
8469 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008470 return *func;
8471}
8472
8473
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008474static MaybeObject* Runtime_AllocateInNewSpace(RUNTIME_CALLING_CONVENTION) {
8475 RUNTIME_GET_ISOLATE;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008476 // Allocate a block of memory in NewSpace (filled with a filler).
8477 // Use as fallback for allocation in generated code when NewSpace
8478 // is full.
8479 ASSERT(args.length() == 1);
8480 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8481 int size = size_smi->value();
8482 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8483 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008484 Heap* heap = isolate->heap();
8485 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008486 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008487 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008488 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008489 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008490 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008491 }
8492 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008493 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008494}
8495
8496
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008497// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008498// array. Returns true if the element was pushed on the stack and
8499// false otherwise.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008500static MaybeObject* Runtime_PushIfAbsent(RUNTIME_CALLING_CONVENTION) {
8501 RUNTIME_GET_ISOLATE;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008502 ASSERT(args.length() == 2);
8503 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008504 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008505 RUNTIME_ASSERT(array->HasFastElements());
8506 int length = Smi::cast(array->length())->value();
8507 FixedArray* elements = FixedArray::cast(array->elements());
8508 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008509 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008510 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008511 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008512 // Strict not needed. Used for cycle detection in Array join implementation.
8513 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8514 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008515 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8516 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008517 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008518}
8519
8520
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008521/**
8522 * A simple visitor visits every element of Array's.
8523 * The backend storage can be a fixed array for fast elements case,
8524 * or a dictionary for sparse array. Since Dictionary is a subtype
8525 * of FixedArray, the class can be used by both fast and slow cases.
8526 * The second parameter of the constructor, fast_elements, specifies
8527 * whether the storage is a FixedArray or Dictionary.
8528 *
8529 * An index limit is used to deal with the situation that a result array
8530 * length overflows 32-bit non-negative integer.
8531 */
8532class ArrayConcatVisitor {
8533 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008534 ArrayConcatVisitor(Isolate* isolate,
8535 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008536 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008537 isolate_(isolate),
8538 storage_(Handle<FixedArray>::cast(
8539 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008540 index_offset_(0u),
8541 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008542
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008543 ~ArrayConcatVisitor() {
8544 clear_storage();
8545 }
8546
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008547 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008548 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008549 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008550
8551 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008552 if (index < static_cast<uint32_t>(storage_->length())) {
8553 storage_->set(index, *elm);
8554 return;
8555 }
8556 // Our initial estimate of length was foiled, possibly by
8557 // getters on the arrays increasing the length of later arrays
8558 // during iteration.
8559 // This shouldn't happen in anything but pathological cases.
8560 SetDictionaryMode(index);
8561 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008562 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008563 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008564 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008565 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008566 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008567 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008568 // Dictionary needed to grow.
8569 clear_storage();
8570 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008571 }
8572}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008573
8574 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008575 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8576 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008577 } else {
8578 index_offset_ += delta;
8579 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008580 }
8581
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008582 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008583 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008584 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008585 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008586 Handle<Map> map;
8587 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008588 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008589 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008590 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008591 }
8592 array->set_map(*map);
8593 array->set_length(*length);
8594 array->set_elements(*storage_);
8595 return array;
8596 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008597
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008598 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008599 // Convert storage to dictionary mode.
8600 void SetDictionaryMode(uint32_t index) {
8601 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008602 Handle<FixedArray> current_storage(*storage_);
8603 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008604 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008605 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8606 for (uint32_t i = 0; i < current_length; i++) {
8607 HandleScope loop_scope;
8608 Handle<Object> element(current_storage->get(i));
8609 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008610 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008611 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008612 if (!new_storage.is_identical_to(slow_storage)) {
8613 slow_storage = loop_scope.CloseAndEscape(new_storage);
8614 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008615 }
8616 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008617 clear_storage();
8618 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008619 fast_elements_ = false;
8620 }
8621
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008622 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008623 isolate_->global_handles()->Destroy(
8624 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008625 }
8626
8627 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008628 storage_ = Handle<FixedArray>::cast(
8629 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008630 }
8631
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008632 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008633 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008634 // Index after last seen index. Always less than or equal to
8635 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008636 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008637 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008638};
8639
8640
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008641static uint32_t EstimateElementCount(Handle<JSArray> array) {
8642 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8643 int element_count = 0;
8644 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008645 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008646 // Fast elements can't have lengths that are not representable by
8647 // a 32-bit signed integer.
8648 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8649 int fast_length = static_cast<int>(length);
8650 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8651 for (int i = 0; i < fast_length; i++) {
8652 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008653 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008654 break;
8655 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008656 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008657 Handle<NumberDictionary> dictionary(
8658 NumberDictionary::cast(array->elements()));
8659 int capacity = dictionary->Capacity();
8660 for (int i = 0; i < capacity; i++) {
8661 Handle<Object> key(dictionary->KeyAt(i));
8662 if (dictionary->IsKey(*key)) {
8663 element_count++;
8664 }
8665 }
8666 break;
8667 }
8668 default:
8669 // External arrays are always dense.
8670 return length;
8671 }
8672 // As an estimate, we assume that the prototype doesn't contain any
8673 // inherited elements.
8674 return element_count;
8675}
8676
8677
8678
8679template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008680static void IterateExternalArrayElements(Isolate* isolate,
8681 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008682 bool elements_are_ints,
8683 bool elements_are_guaranteed_smis,
8684 ArrayConcatVisitor* visitor) {
8685 Handle<ExternalArrayClass> array(
8686 ExternalArrayClass::cast(receiver->elements()));
8687 uint32_t len = static_cast<uint32_t>(array->length());
8688
8689 ASSERT(visitor != NULL);
8690 if (elements_are_ints) {
8691 if (elements_are_guaranteed_smis) {
8692 for (uint32_t j = 0; j < len; j++) {
8693 HandleScope loop_scope;
8694 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8695 visitor->visit(j, e);
8696 }
8697 } else {
8698 for (uint32_t j = 0; j < len; j++) {
8699 HandleScope loop_scope;
8700 int64_t val = static_cast<int64_t>(array->get(j));
8701 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8702 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8703 visitor->visit(j, e);
8704 } else {
8705 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008706 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008707 visitor->visit(j, e);
8708 }
8709 }
8710 }
8711 } else {
8712 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008713 HandleScope loop_scope(isolate);
8714 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008715 visitor->visit(j, e);
8716 }
8717 }
8718}
8719
8720
8721// Used for sorting indices in a List<uint32_t>.
8722static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8723 uint32_t a = *ap;
8724 uint32_t b = *bp;
8725 return (a == b) ? 0 : (a < b) ? -1 : 1;
8726}
8727
8728
8729static void CollectElementIndices(Handle<JSObject> object,
8730 uint32_t range,
8731 List<uint32_t>* indices) {
8732 JSObject::ElementsKind kind = object->GetElementsKind();
8733 switch (kind) {
8734 case JSObject::FAST_ELEMENTS: {
8735 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8736 uint32_t length = static_cast<uint32_t>(elements->length());
8737 if (range < length) length = range;
8738 for (uint32_t i = 0; i < length; i++) {
8739 if (!elements->get(i)->IsTheHole()) {
8740 indices->Add(i);
8741 }
8742 }
8743 break;
8744 }
8745 case JSObject::DICTIONARY_ELEMENTS: {
8746 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008747 uint32_t capacity = dict->Capacity();
8748 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008749 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008750 Handle<Object> k(dict->KeyAt(j));
8751 if (dict->IsKey(*k)) {
8752 ASSERT(k->IsNumber());
8753 uint32_t index = static_cast<uint32_t>(k->Number());
8754 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008755 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008756 }
8757 }
8758 }
8759 break;
8760 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008761 default: {
8762 int dense_elements_length;
8763 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008764 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008765 dense_elements_length =
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008766 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008767 break;
8768 }
8769 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8770 dense_elements_length =
8771 ExternalByteArray::cast(object->elements())->length();
8772 break;
8773 }
8774 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8775 dense_elements_length =
8776 ExternalUnsignedByteArray::cast(object->elements())->length();
8777 break;
8778 }
8779 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8780 dense_elements_length =
8781 ExternalShortArray::cast(object->elements())->length();
8782 break;
8783 }
8784 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8785 dense_elements_length =
8786 ExternalUnsignedShortArray::cast(object->elements())->length();
8787 break;
8788 }
8789 case JSObject::EXTERNAL_INT_ELEMENTS: {
8790 dense_elements_length =
8791 ExternalIntArray::cast(object->elements())->length();
8792 break;
8793 }
8794 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8795 dense_elements_length =
8796 ExternalUnsignedIntArray::cast(object->elements())->length();
8797 break;
8798 }
8799 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8800 dense_elements_length =
8801 ExternalFloatArray::cast(object->elements())->length();
8802 break;
8803 }
8804 default:
8805 UNREACHABLE();
8806 dense_elements_length = 0;
8807 break;
8808 }
8809 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8810 if (range <= length) {
8811 length = range;
8812 // We will add all indices, so we might as well clear it first
8813 // and avoid duplicates.
8814 indices->Clear();
8815 }
8816 for (uint32_t i = 0; i < length; i++) {
8817 indices->Add(i);
8818 }
8819 if (length == range) return; // All indices accounted for already.
8820 break;
8821 }
8822 }
8823
8824 Handle<Object> prototype(object->GetPrototype());
8825 if (prototype->IsJSObject()) {
8826 // The prototype will usually have no inherited element indices,
8827 // but we have to check.
8828 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8829 }
8830}
8831
8832
8833/**
8834 * A helper function that visits elements of a JSArray in numerical
8835 * order.
8836 *
8837 * The visitor argument called for each existing element in the array
8838 * with the element index and the element's value.
8839 * Afterwards it increments the base-index of the visitor by the array
8840 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008841 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008842 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008843static bool IterateElements(Isolate* isolate,
8844 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008845 ArrayConcatVisitor* visitor) {
8846 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8847 switch (receiver->GetElementsKind()) {
8848 case JSObject::FAST_ELEMENTS: {
8849 // Run through the elements FixedArray and use HasElement and GetElement
8850 // to check the prototype for missing elements.
8851 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8852 int fast_length = static_cast<int>(length);
8853 ASSERT(fast_length <= elements->length());
8854 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008855 HandleScope loop_scope(isolate);
8856 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008857 if (!element_value->IsTheHole()) {
8858 visitor->visit(j, element_value);
8859 } else if (receiver->HasElement(j)) {
8860 // Call GetElement on receiver, not its prototype, or getters won't
8861 // have the correct receiver.
8862 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008863 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008864 visitor->visit(j, element_value);
8865 }
8866 }
8867 break;
8868 }
8869 case JSObject::DICTIONARY_ELEMENTS: {
8870 Handle<NumberDictionary> dict(receiver->element_dictionary());
8871 List<uint32_t> indices(dict->Capacity() / 2);
8872 // Collect all indices in the object and the prototypes less
8873 // than length. This might introduce duplicates in the indices list.
8874 CollectElementIndices(receiver, length, &indices);
8875 indices.Sort(&compareUInt32);
8876 int j = 0;
8877 int n = indices.length();
8878 while (j < n) {
8879 HandleScope loop_scope;
8880 uint32_t index = indices[j];
8881 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008882 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008883 visitor->visit(index, element);
8884 // Skip to next different index (i.e., omit duplicates).
8885 do {
8886 j++;
8887 } while (j < n && indices[j] == index);
8888 }
8889 break;
8890 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008891 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
8892 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
8893 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008894 for (uint32_t j = 0; j < length; j++) {
8895 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8896 visitor->visit(j, e);
8897 }
8898 break;
8899 }
8900 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8901 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008902 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008903 break;
8904 }
8905 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8906 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008907 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008908 break;
8909 }
8910 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8911 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008912 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008913 break;
8914 }
8915 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8916 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008917 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008918 break;
8919 }
8920 case JSObject::EXTERNAL_INT_ELEMENTS: {
8921 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008922 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008923 break;
8924 }
8925 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8926 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008927 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008928 break;
8929 }
8930 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8931 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008932 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008933 break;
8934 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008935 default:
8936 UNREACHABLE();
8937 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008938 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008939 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008940 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008941}
8942
8943
8944/**
8945 * Array::concat implementation.
8946 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008947 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008948 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008949 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008950static MaybeObject* Runtime_ArrayConcat(RUNTIME_CALLING_CONVENTION) {
8951 RUNTIME_GET_ISOLATE;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008952 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008953 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008954
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008955 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8956 int argument_count = static_cast<int>(arguments->length()->Number());
8957 RUNTIME_ASSERT(arguments->HasFastElements());
8958 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008959
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008960 // Pass 1: estimate the length and number of elements of the result.
8961 // The actual length can be larger if any of the arguments have getters
8962 // that mutate other arguments (but will otherwise be precise).
8963 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008964
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008965 uint32_t estimate_result_length = 0;
8966 uint32_t estimate_nof_elements = 0;
8967 {
8968 for (int i = 0; i < argument_count; i++) {
8969 HandleScope loop_scope;
8970 Handle<Object> obj(elements->get(i));
8971 uint32_t length_estimate;
8972 uint32_t element_estimate;
8973 if (obj->IsJSArray()) {
8974 Handle<JSArray> array(Handle<JSArray>::cast(obj));
8975 length_estimate =
8976 static_cast<uint32_t>(array->length()->Number());
8977 element_estimate =
8978 EstimateElementCount(array);
8979 } else {
8980 length_estimate = 1;
8981 element_estimate = 1;
8982 }
8983 // Avoid overflows by capping at kMaxElementCount.
8984 if (JSObject::kMaxElementCount - estimate_result_length <
8985 length_estimate) {
8986 estimate_result_length = JSObject::kMaxElementCount;
8987 } else {
8988 estimate_result_length += length_estimate;
8989 }
8990 if (JSObject::kMaxElementCount - estimate_nof_elements <
8991 element_estimate) {
8992 estimate_nof_elements = JSObject::kMaxElementCount;
8993 } else {
8994 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008995 }
8996 }
8997 }
8998
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008999 // If estimated number of elements is more than half of length, a
9000 // fixed array (fast case) is more time and space-efficient than a
9001 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009002 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009003
9004 Handle<FixedArray> storage;
9005 if (fast_case) {
9006 // The backing storage array must have non-existing elements to
9007 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009008 storage = isolate->factory()->NewFixedArrayWithHoles(
9009 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009010 } else {
9011 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9012 uint32_t at_least_space_for = estimate_nof_elements +
9013 (estimate_nof_elements >> 2);
9014 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009015 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009016 }
9017
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009018 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009019
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009020 for (int i = 0; i < argument_count; i++) {
9021 Handle<Object> obj(elements->get(i));
9022 if (obj->IsJSArray()) {
9023 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009024 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009025 return Failure::Exception();
9026 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009027 } else {
9028 visitor.visit(0, obj);
9029 visitor.increase_index_offset(1);
9030 }
9031 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009032
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009033 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009034}
9035
9036
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009037// This will not allocate (flatten the string), but it may run
9038// very slowly for very deeply nested ConsStrings. For debugging use only.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009039static MaybeObject* Runtime_GlobalPrint(RUNTIME_CALLING_CONVENTION) {
9040 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009041 NoHandleAllocation ha;
9042 ASSERT(args.length() == 1);
9043
9044 CONVERT_CHECKED(String, string, args[0]);
9045 StringInputBuffer buffer(string);
9046 while (buffer.has_more()) {
9047 uint16_t character = buffer.GetNext();
9048 PrintF("%c", character);
9049 }
9050 return string;
9051}
9052
ager@chromium.org5ec48922009-05-05 07:25:34 +00009053// Moves all own elements of an object, that are below a limit, to positions
9054// starting at zero. All undefined values are placed after non-undefined values,
9055// and are followed by non-existing element. Does not change the length
9056// property.
9057// Returns the number of non-undefined elements collected.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009058static MaybeObject* Runtime_RemoveArrayHoles(RUNTIME_CALLING_CONVENTION) {
9059 RUNTIME_GET_ISOLATE;
ager@chromium.org5ec48922009-05-05 07:25:34 +00009060 ASSERT(args.length() == 2);
9061 CONVERT_CHECKED(JSObject, object, args[0]);
9062 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9063 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009064}
9065
9066
9067// Move contents of argument 0 (an array) to argument 1 (an array)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009068static MaybeObject* Runtime_MoveArrayContents(RUNTIME_CALLING_CONVENTION) {
9069 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009070 ASSERT(args.length() == 2);
9071 CONVERT_CHECKED(JSArray, from, args[0]);
9072 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009073 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009074 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009075 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9076 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009077 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009078 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009079 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009080 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009081 Object* new_map;
9082 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009083 to->set_map(Map::cast(new_map));
9084 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009085 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009086 Object* obj;
9087 { MaybeObject* maybe_obj = from->ResetElements();
9088 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9089 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009090 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009091 return to;
9092}
9093
9094
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009095// How many elements does this object/array have?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009096static MaybeObject* Runtime_EstimateNumberOfElements(
9097 RUNTIME_CALLING_CONVENTION) {
9098 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009099 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009100 CONVERT_CHECKED(JSObject, object, args[0]);
9101 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009102 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009103 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009104 } else if (object->IsJSArray()) {
9105 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009106 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009107 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009108 }
9109}
9110
9111
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009112static MaybeObject* Runtime_SwapElements(RUNTIME_CALLING_CONVENTION) {
9113 RUNTIME_GET_ISOLATE;
9114 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009115
9116 ASSERT_EQ(3, args.length());
9117
ager@chromium.orgac091b72010-05-05 07:34:42 +00009118 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009119 Handle<Object> key1 = args.at<Object>(1);
9120 Handle<Object> key2 = args.at<Object>(2);
9121
9122 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009123 if (!key1->ToArrayIndex(&index1)
9124 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009125 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009126 }
9127
ager@chromium.orgac091b72010-05-05 07:34:42 +00009128 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9129 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009130 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009131 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009132 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009133
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009134 RETURN_IF_EMPTY_HANDLE(isolate,
9135 SetElement(jsobject, index1, tmp2, kStrictMode));
9136 RETURN_IF_EMPTY_HANDLE(isolate,
9137 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009139 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009140}
9141
9142
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009143// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009144// might have elements. Can either return keys (positive integers) or
9145// intervals (pair of a negative integer (-start-1) followed by a
9146// positive (length)) or undefined values.
9147// Intervals can span over some keys that are not in the object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009148static MaybeObject* Runtime_GetArrayKeys(RUNTIME_CALLING_CONVENTION) {
9149 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009150 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009151 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009152 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009153 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009154 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009155 // Create an array and get all the keys into it, then remove all the
9156 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009157 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009158 int keys_length = keys->length();
9159 for (int i = 0; i < keys_length; i++) {
9160 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009161 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009162 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009163 // Zap invalid keys.
9164 keys->set_undefined(i);
9165 }
9166 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009167 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009168 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009169 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009170 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009171 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009172 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009173 uint32_t actual_length =
9174 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009175 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009176 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009177 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009178 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009179 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009180 }
9181}
9182
9183
9184// DefineAccessor takes an optional final argument which is the
9185// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9186// to the way accessors are implemented, it is set for both the getter
9187// and setter on the first call to DefineAccessor and ignored on
9188// subsequent calls.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009189static MaybeObject* Runtime_DefineAccessor(RUNTIME_CALLING_CONVENTION) {
9190 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009191 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9192 // Compute attributes.
9193 PropertyAttributes attributes = NONE;
9194 if (args.length() == 5) {
9195 CONVERT_CHECKED(Smi, attrs, args[4]);
9196 int value = attrs->value();
9197 // Only attribute bits should be set.
9198 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9199 attributes = static_cast<PropertyAttributes>(value);
9200 }
9201
9202 CONVERT_CHECKED(JSObject, obj, args[0]);
9203 CONVERT_CHECKED(String, name, args[1]);
9204 CONVERT_CHECKED(Smi, flag, args[2]);
9205 CONVERT_CHECKED(JSFunction, fun, args[3]);
9206 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9207}
9208
9209
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009210static MaybeObject* Runtime_LookupAccessor(RUNTIME_CALLING_CONVENTION) {
9211 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009212 ASSERT(args.length() == 3);
9213 CONVERT_CHECKED(JSObject, obj, args[0]);
9214 CONVERT_CHECKED(String, name, args[1]);
9215 CONVERT_CHECKED(Smi, flag, args[2]);
9216 return obj->LookupAccessor(name, flag->value() == 0);
9217}
9218
9219
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009220#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009221static MaybeObject* Runtime_DebugBreak(RUNTIME_CALLING_CONVENTION) {
9222 RUNTIME_GET_ISOLATE;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009223 ASSERT(args.length() == 0);
9224 return Execution::DebugBreakHelper();
9225}
9226
9227
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009228// Helper functions for wrapping and unwrapping stack frame ids.
9229static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009230 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009231 return Smi::FromInt(id >> 2);
9232}
9233
9234
9235static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9236 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9237}
9238
9239
9240// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009241// args[0]: debug event listener function to set or null or undefined for
9242// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009243// args[1]: object supplied during callback
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009244static MaybeObject* Runtime_SetDebugEventListener(RUNTIME_CALLING_CONVENTION) {
9245 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009246 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009247 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9248 args[0]->IsUndefined() ||
9249 args[0]->IsNull());
9250 Handle<Object> callback = args.at<Object>(0);
9251 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009252 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009253
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009254 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009255}
9256
9257
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009258static MaybeObject* Runtime_Break(RUNTIME_CALLING_CONVENTION) {
9259 RUNTIME_GET_ISOLATE;
mads.s.ager31e71382008-08-13 09:32:07 +00009260 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009261 isolate->stack_guard()->DebugBreak();
9262 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009263}
9264
9265
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009266static MaybeObject* DebugLookupResultValue(Heap* heap,
9267 Object* receiver,
9268 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009269 LookupResult* result,
9270 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009271 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009272 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009273 case NORMAL:
9274 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009275 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009276 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009277 }
9278 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009279 case FIELD:
9280 value =
9281 JSObject::cast(
9282 result->holder())->FastPropertyAt(result->GetFieldIndex());
9283 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009284 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009285 }
9286 return value;
9287 case CONSTANT_FUNCTION:
9288 return result->GetConstantFunction();
9289 case CALLBACKS: {
9290 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009291 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009292 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009293 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009294 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009295 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009296 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009297 maybe_value = heap->isolate()->pending_exception();
9298 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009299 if (caught_exception != NULL) {
9300 *caught_exception = true;
9301 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009302 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009303 }
9304 return value;
9305 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009306 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009307 }
9308 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009309 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009310 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009311 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009312 case CONSTANT_TRANSITION:
9313 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009314 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009315 default:
9316 UNREACHABLE();
9317 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009318 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009319 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009320}
9321
9322
ager@chromium.org32912102009-01-16 10:38:43 +00009323// Get debugger related details for an object property.
9324// args[0]: object holding property
9325// args[1]: name of the property
9326//
9327// The array returned contains the following information:
9328// 0: Property value
9329// 1: Property details
9330// 2: Property value is exception
9331// 3: Getter function if defined
9332// 4: Setter function if defined
9333// Items 2-4 are only filled if the property has either a getter or a setter
9334// defined through __defineGetter__ and/or __defineSetter__.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009335static MaybeObject* Runtime_DebugGetPropertyDetails(
9336 RUNTIME_CALLING_CONVENTION) {
9337 RUNTIME_GET_ISOLATE;
9338 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009339
9340 ASSERT(args.length() == 2);
9341
9342 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9343 CONVERT_ARG_CHECKED(String, name, 1);
9344
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009345 // Make sure to set the current context to the context before the debugger was
9346 // entered (if the debugger is entered). The reason for switching context here
9347 // is that for some property lookups (accessors and interceptors) callbacks
9348 // into the embedding application can occour, and the embedding application
9349 // could have the assumption that its own global context is the current
9350 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009351 SaveContext save(isolate);
9352 if (isolate->debug()->InDebugger()) {
9353 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009354 }
9355
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009356 // Skip the global proxy as it has no properties and always delegates to the
9357 // real global object.
9358 if (obj->IsJSGlobalProxy()) {
9359 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9360 }
9361
9362
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009363 // Check if the name is trivially convertible to an index and get the element
9364 // if so.
9365 uint32_t index;
9366 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009367 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009368 Object* element_or_char;
9369 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009370 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009371 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9372 return maybe_element_or_char;
9373 }
9374 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009375 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009376 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009377 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009378 }
9379
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009380 // Find the number of objects making up this.
9381 int length = LocalPrototypeChainLength(*obj);
9382
9383 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009384 Handle<JSObject> jsproto = obj;
9385 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009386 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009387 jsproto->LocalLookup(*name, &result);
9388 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009389 // LookupResult is not GC safe as it holds raw object pointers.
9390 // GC can happen later in this code so put the required fields into
9391 // local variables using handles when required for later use.
9392 PropertyType result_type = result.type();
9393 Handle<Object> result_callback_obj;
9394 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009395 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9396 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009397 }
9398 Smi* property_details = result.GetPropertyDetails().AsSmi();
9399 // DebugLookupResultValue can cause GC so details from LookupResult needs
9400 // to be copied to handles before this.
9401 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009402 Object* raw_value;
9403 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009404 DebugLookupResultValue(isolate->heap(), *obj, *name,
9405 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009406 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9407 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009408 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009409
9410 // If the callback object is a fixed array then it contains JavaScript
9411 // getter and/or setter.
9412 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9413 result_callback_obj->IsFixedArray();
9414 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009415 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009416 details->set(0, *value);
9417 details->set(1, property_details);
9418 if (hasJavaScriptAccessors) {
9419 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009420 caught_exception ? isolate->heap()->true_value()
9421 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009422 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9423 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9424 }
9425
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009426 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009427 }
9428 if (i < length - 1) {
9429 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9430 }
9431 }
9432
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009433 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009434}
9435
9436
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009437static MaybeObject* Runtime_DebugGetProperty(RUNTIME_CALLING_CONVENTION) {
9438 RUNTIME_GET_ISOLATE;
9439 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009440
9441 ASSERT(args.length() == 2);
9442
9443 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9444 CONVERT_ARG_CHECKED(String, name, 1);
9445
9446 LookupResult result;
9447 obj->Lookup(*name, &result);
9448 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009449 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009450 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009451 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009452}
9453
9454
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009455// Return the property type calculated from the property details.
9456// args[0]: smi with property details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009457static MaybeObject* Runtime_DebugPropertyTypeFromDetails(
9458 RUNTIME_CALLING_CONVENTION) {
9459 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009460 ASSERT(args.length() == 1);
9461 CONVERT_CHECKED(Smi, details, args[0]);
9462 PropertyType type = PropertyDetails(details).type();
9463 return Smi::FromInt(static_cast<int>(type));
9464}
9465
9466
9467// Return the property attribute calculated from the property details.
9468// args[0]: smi with property details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009469static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(
9470 RUNTIME_CALLING_CONVENTION) {
9471 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009472 ASSERT(args.length() == 1);
9473 CONVERT_CHECKED(Smi, details, args[0]);
9474 PropertyAttributes attributes = PropertyDetails(details).attributes();
9475 return Smi::FromInt(static_cast<int>(attributes));
9476}
9477
9478
9479// Return the property insertion index calculated from the property details.
9480// args[0]: smi with property details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009481static MaybeObject* Runtime_DebugPropertyIndexFromDetails(
9482 RUNTIME_CALLING_CONVENTION) {
9483 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009484 ASSERT(args.length() == 1);
9485 CONVERT_CHECKED(Smi, details, args[0]);
9486 int index = PropertyDetails(details).index();
9487 return Smi::FromInt(index);
9488}
9489
9490
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009491// Return property value from named interceptor.
9492// args[0]: object
9493// args[1]: property name
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009494static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(
9495 RUNTIME_CALLING_CONVENTION) {
9496 RUNTIME_GET_ISOLATE;
9497 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009498 ASSERT(args.length() == 2);
9499 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9500 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9501 CONVERT_ARG_CHECKED(String, name, 1);
9502
9503 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009504 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009505}
9506
9507
9508// Return element value from indexed interceptor.
9509// args[0]: object
9510// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00009511static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009512 RUNTIME_CALLING_CONVENTION) {
9513 RUNTIME_GET_ISOLATE;
9514 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009515 ASSERT(args.length() == 2);
9516 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9517 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9518 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9519
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009520 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009521}
9522
9523
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009524static MaybeObject* Runtime_CheckExecutionState(RUNTIME_CALLING_CONVENTION) {
9525 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009526 ASSERT(args.length() >= 1);
9527 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009528 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009529 if (isolate->debug()->break_id() == 0 ||
9530 break_id != isolate->debug()->break_id()) {
9531 return isolate->Throw(
9532 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009533 }
9534
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009535 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009536}
9537
9538
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009539static MaybeObject* Runtime_GetFrameCount(RUNTIME_CALLING_CONVENTION) {
9540 RUNTIME_GET_ISOLATE;
9541 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009542 ASSERT(args.length() == 1);
9543
9544 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009545 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009546 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args, isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009547 if (!maybe_result->ToObject(&result)) return maybe_result;
9548 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009549
9550 // Count all frames which are relevant to debugging stack trace.
9551 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009552 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009553 if (id == StackFrame::NO_ID) {
9554 // If there is no JavaScript stack frame count is 0.
9555 return Smi::FromInt(0);
9556 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009557 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
9558 return Smi::FromInt(n);
9559}
9560
9561
9562static const int kFrameDetailsFrameIdIndex = 0;
9563static const int kFrameDetailsReceiverIndex = 1;
9564static const int kFrameDetailsFunctionIndex = 2;
9565static const int kFrameDetailsArgumentCountIndex = 3;
9566static const int kFrameDetailsLocalCountIndex = 4;
9567static const int kFrameDetailsSourcePositionIndex = 5;
9568static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009569static const int kFrameDetailsAtReturnIndex = 7;
9570static const int kFrameDetailsDebuggerFrameIndex = 8;
9571static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009572
9573// Return an array with frame details
9574// args[0]: number: break id
9575// args[1]: number: frame index
9576//
9577// The array returned contains the following information:
9578// 0: Frame id
9579// 1: Receiver
9580// 2: Function
9581// 3: Argument count
9582// 4: Local count
9583// 5: Source position
9584// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009585// 7: Is at return
9586// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009587// Arguments name, value
9588// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009589// Return value if any
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009590static MaybeObject* Runtime_GetFrameDetails(RUNTIME_CALLING_CONVENTION) {
9591 RUNTIME_GET_ISOLATE;
9592 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009593 ASSERT(args.length() == 2);
9594
9595 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009596 Object* check;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009597 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args, isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009598 if (!maybe_check->ToObject(&check)) return maybe_check;
9599 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009600 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009601 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009602
9603 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009604 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009605 if (id == StackFrame::NO_ID) {
9606 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009607 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009608 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009609 int count = 0;
9610 JavaScriptFrameIterator it(id);
9611 for (; !it.done(); it.Advance()) {
9612 if (count == index) break;
9613 count++;
9614 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009615 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009616
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009617 bool is_optimized_frame =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009618 it.frame()->LookupCode(isolate)->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009619
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009620 // Traverse the saved contexts chain to find the active context for the
9621 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009622 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009623 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009624 save = save->prev();
9625 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009626 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009627
9628 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009629 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009630
9631 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009632 int position =
9633 it.frame()->LookupCode(isolate)->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009634
9635 // Check for constructor frame.
9636 bool constructor = it.frame()->IsConstructor();
9637
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009638 // Get scope info and read from it for local variable information.
9639 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009640 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009641 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009642
9643 // Get the context.
9644 Handle<Context> context(Context::cast(it.frame()->context()));
9645
9646 // Get the locals names and values into a temporary array.
9647 //
9648 // TODO(1240907): Hide compiler-introduced stack variables
9649 // (e.g. .result)? For users of the debugger, they will probably be
9650 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009651 Handle<FixedArray> locals =
9652 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009653
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009654 // Fill in the names of the locals.
9655 for (int i = 0; i < info.NumberOfLocals(); i++) {
9656 locals->set(i * 2, *info.LocalName(i));
9657 }
9658
9659 // Fill in the values of the locals.
9660 for (int i = 0; i < info.NumberOfLocals(); i++) {
9661 if (is_optimized_frame) {
9662 // If we are inspecting an optimized frame use undefined as the
9663 // value for all locals.
9664 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009665 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009666 // for locals in optimized frames.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009667 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009668 } else if (i < info.number_of_stack_slots()) {
9669 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009670 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9671 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009672 // Traverse the context chain to the function context as all local
9673 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009674 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009675 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009676 context = Handle<Context>(context->previous());
9677 }
9678 ASSERT(context->is_function_context());
9679 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009680 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009681 }
9682 }
9683
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009684 // Check whether this frame is positioned at return. If not top
9685 // frame or if the frame is optimized it cannot be at a return.
9686 bool at_return = false;
9687 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009688 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009689 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009690
9691 // If positioned just before return find the value to be returned and add it
9692 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009693 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009694 if (at_return) {
9695 StackFrameIterator it2;
9696 Address internal_frame_sp = NULL;
9697 while (!it2.done()) {
9698 if (it2.frame()->is_internal()) {
9699 internal_frame_sp = it2.frame()->sp();
9700 } else {
9701 if (it2.frame()->is_java_script()) {
9702 if (it2.frame()->id() == it.frame()->id()) {
9703 // The internal frame just before the JavaScript frame contains the
9704 // value to return on top. A debug break at return will create an
9705 // internal frame to store the return value (eax/rax/r0) before
9706 // entering the debug break exit frame.
9707 if (internal_frame_sp != NULL) {
9708 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009709 Handle<Object>(Memory::Object_at(internal_frame_sp),
9710 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009711 break;
9712 }
9713 }
9714 }
9715
9716 // Indicate that the previous frame was not an internal frame.
9717 internal_frame_sp = NULL;
9718 }
9719 it2.Advance();
9720 }
9721 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009722
9723 // Now advance to the arguments adapter frame (if any). It contains all
9724 // the provided parameters whereas the function frame always have the number
9725 // of arguments matching the functions parameters. The rest of the
9726 // information (except for what is collected above) is the same.
9727 it.AdvanceToArgumentsFrame();
9728
9729 // Find the number of arguments to fill. At least fill the number of
9730 // parameters for the function and fill more if more parameters are provided.
9731 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009732 if (argument_count < it.frame()->ComputeParametersCount()) {
9733 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009734 }
9735
9736 // Calculate the size of the result.
9737 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009738 2 * (argument_count + info.NumberOfLocals()) +
9739 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009740 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009741
9742 // Add the frame id.
9743 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9744
9745 // Add the function (same as in function frame).
9746 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9747
9748 // Add the arguments count.
9749 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9750
9751 // Add the locals count
9752 details->set(kFrameDetailsLocalCountIndex,
9753 Smi::FromInt(info.NumberOfLocals()));
9754
9755 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009756 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009757 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9758 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009759 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009760 }
9761
9762 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009763 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009764
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009765 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009766 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009767
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009768 // Add information on whether this frame is invoked in the debugger context.
9769 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009770 heap->ToBoolean(*save->context() ==
9771 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009772
9773 // Fill the dynamic part.
9774 int details_index = kFrameDetailsFirstDynamicIndex;
9775
9776 // Add arguments name and value.
9777 for (int i = 0; i < argument_count; i++) {
9778 // Name of the argument.
9779 if (i < info.number_of_parameters()) {
9780 details->set(details_index++, *info.parameter_name(i));
9781 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009782 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009783 }
9784
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009785 // Parameter value. If we are inspecting an optimized frame, use
9786 // undefined as the value.
9787 //
9788 // TODO(3141533): We should be able to get the actual parameter
9789 // value for optimized frames.
9790 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009791 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009792 details->set(details_index++, it.frame()->GetParameter(i));
9793 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009794 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009795 }
9796 }
9797
9798 // Add locals name and value from the temporary copy from the function frame.
9799 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9800 details->set(details_index++, locals->get(i));
9801 }
9802
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009803 // Add the value being returned.
9804 if (at_return) {
9805 details->set(details_index++, *return_value);
9806 }
9807
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009808 // Add the receiver (same as in function frame).
9809 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9810 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009811 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009812 if (!receiver->IsJSObject()) {
9813 // If the receiver is NOT a JSObject we have hit an optimization
9814 // where a value object is not converted into a wrapped JS objects.
9815 // To hide this optimization from the debugger, we wrap the receiver
9816 // by creating correct wrapper object based on the calling frame's
9817 // global context.
9818 it.Advance();
9819 Handle<Context> calling_frames_global_context(
9820 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009821 receiver =
9822 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009823 }
9824 details->set(kFrameDetailsReceiverIndex, *receiver);
9825
9826 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009827 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009828}
9829
9830
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009831// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009832static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009833 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009834 Handle<SerializedScopeInfo> serialized_scope_info,
9835 ScopeInfo<>& scope_info,
9836 Handle<Context> context,
9837 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009838 // Fill all context locals to the context extension.
9839 for (int i = Context::MIN_CONTEXT_SLOTS;
9840 i < scope_info.number_of_context_slots();
9841 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009842 int context_index = serialized_scope_info->ContextSlotIndex(
9843 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009844
9845 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009846 if (*scope_info.context_slot_name(i) !=
9847 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009848 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009849 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009850 SetProperty(scope_object,
9851 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009852 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009853 NONE,
9854 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009855 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009856 }
9857 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009858
9859 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009860}
9861
9862
9863// Create a plain JSObject which materializes the local scope for the specified
9864// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009865static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
9866 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009867 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009868 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009869 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9870 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009871
9872 // Allocate and initialize a JSObject with all the arguments, stack locals
9873 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009874 Handle<JSObject> local_scope =
9875 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009876
9877 // First fill all parameters.
9878 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009879 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009880 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009881 SetProperty(local_scope,
9882 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009883 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009884 NONE,
9885 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009886 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009887 }
9888
9889 // Second fill all stack locals.
9890 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009891 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009892 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009893 SetProperty(local_scope,
9894 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009895 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009896 NONE,
9897 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009898 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009899 }
9900
9901 // Third fill all context locals.
9902 Handle<Context> frame_context(Context::cast(frame->context()));
9903 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009904 if (!CopyContextLocalsToScopeObject(isolate,
9905 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009906 function_context, local_scope)) {
9907 return Handle<JSObject>();
9908 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009909
9910 // Finally copy any properties from the function context extension. This will
9911 // be variables introduced by eval.
9912 if (function_context->closure() == *function) {
9913 if (function_context->has_extension() &&
9914 !function_context->IsGlobalContext()) {
9915 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009916 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009917 for (int i = 0; i < keys->length(); i++) {
9918 // Names of variables introduced by eval are strings.
9919 ASSERT(keys->get(i)->IsString());
9920 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009921 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009922 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009923 SetProperty(local_scope,
9924 key,
9925 GetProperty(ext, key),
9926 NONE,
9927 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009928 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009929 }
9930 }
9931 }
9932 return local_scope;
9933}
9934
9935
9936// Create a plain JSObject which materializes the closure content for the
9937// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009938static Handle<JSObject> MaterializeClosure(Isolate* isolate,
9939 Handle<Context> context) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009940 ASSERT(context->is_function_context());
9941
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009942 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009943 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9944 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009945
9946 // Allocate and initialize a JSObject with all the content of theis function
9947 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009948 Handle<JSObject> closure_scope =
9949 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009950
9951 // Check whether the arguments shadow object exists.
9952 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009953 shared->scope_info()->ContextSlotIndex(
9954 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009955 if (arguments_shadow_index >= 0) {
9956 // In this case all the arguments are available in the arguments shadow
9957 // object.
9958 Handle<JSObject> arguments_shadow(
9959 JSObject::cast(context->get(arguments_shadow_index)));
9960 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009961 // We don't expect exception-throwing getters on the arguments shadow.
9962 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009963 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009964 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009965 SetProperty(closure_scope,
9966 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009967 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009968 NONE,
9969 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009970 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009971 }
9972 }
9973
9974 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009975 if (!CopyContextLocalsToScopeObject(isolate,
9976 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009977 context, closure_scope)) {
9978 return Handle<JSObject>();
9979 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009980
9981 // Finally copy any properties from the function context extension. This will
9982 // be variables introduced by eval.
9983 if (context->has_extension()) {
9984 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009985 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009986 for (int i = 0; i < keys->length(); i++) {
9987 // Names of variables introduced by eval are strings.
9988 ASSERT(keys->get(i)->IsString());
9989 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009990 RETURN_IF_EMPTY_HANDLE_VALUE(
9991 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009992 SetProperty(closure_scope,
9993 key,
9994 GetProperty(ext, key),
9995 NONE,
9996 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009997 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009998 }
9999 }
10000
10001 return closure_scope;
10002}
10003
10004
10005// Iterate over the actual scopes visible from a stack frame. All scopes are
10006// backed by an actual context except the local scope, which is inserted
10007// "artifically" in the context chain.
10008class ScopeIterator {
10009 public:
10010 enum ScopeType {
10011 ScopeTypeGlobal = 0,
10012 ScopeTypeLocal,
10013 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010014 ScopeTypeClosure,
10015 // Every catch block contains an implicit with block (its parameter is
10016 // a JSContextExtensionObject) that extends current scope with a variable
10017 // holding exception object. Such with blocks are treated as scopes of their
10018 // own type.
10019 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010020 };
10021
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010022 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
10023 : isolate_(isolate),
10024 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010025 function_(JSFunction::cast(frame->function())),
10026 context_(Context::cast(frame->context())),
10027 local_done_(false),
10028 at_local_(false) {
10029
10030 // Check whether the first scope is actually a local scope.
10031 if (context_->IsGlobalContext()) {
10032 // If there is a stack slot for .result then this local scope has been
10033 // created for evaluating top level code and it is not a real local scope.
10034 // Checking for the existence of .result seems fragile, but the scope info
10035 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010036 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010037 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010038 at_local_ = index < 0;
10039 } else if (context_->is_function_context()) {
10040 at_local_ = true;
10041 }
10042 }
10043
10044 // More scopes?
10045 bool Done() { return context_.is_null(); }
10046
10047 // Move to the next scope.
10048 void Next() {
10049 // If at a local scope mark the local scope as passed.
10050 if (at_local_) {
10051 at_local_ = false;
10052 local_done_ = true;
10053
10054 // If the current context is not associated with the local scope the
10055 // current context is the next real scope, so don't move to the next
10056 // context in this case.
10057 if (context_->closure() != *function_) {
10058 return;
10059 }
10060 }
10061
10062 // The global scope is always the last in the chain.
10063 if (context_->IsGlobalContext()) {
10064 context_ = Handle<Context>();
10065 return;
10066 }
10067
10068 // Move to the next context.
10069 if (context_->is_function_context()) {
10070 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
10071 } else {
10072 context_ = Handle<Context>(context_->previous());
10073 }
10074
10075 // If passing the local scope indicate that the current scope is now the
10076 // local scope.
10077 if (!local_done_ &&
10078 (context_->IsGlobalContext() || (context_->is_function_context()))) {
10079 at_local_ = true;
10080 }
10081 }
10082
10083 // Return the type of the current scope.
10084 int Type() {
10085 if (at_local_) {
10086 return ScopeTypeLocal;
10087 }
10088 if (context_->IsGlobalContext()) {
10089 ASSERT(context_->global()->IsGlobalObject());
10090 return ScopeTypeGlobal;
10091 }
10092 if (context_->is_function_context()) {
10093 return ScopeTypeClosure;
10094 }
10095 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +000010096 // Current scope is either an explicit with statement or a with statement
10097 // implicitely generated for a catch block.
10098 // If the extension object here is a JSContextExtensionObject then
10099 // current with statement is one frome a catch block otherwise it's a
10100 // regular with statement.
10101 if (context_->extension()->IsJSContextExtensionObject()) {
10102 return ScopeTypeCatch;
10103 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010104 return ScopeTypeWith;
10105 }
10106
10107 // Return the JavaScript object with the content of the current scope.
10108 Handle<JSObject> ScopeObject() {
10109 switch (Type()) {
10110 case ScopeIterator::ScopeTypeGlobal:
10111 return Handle<JSObject>(CurrentContext()->global());
10112 break;
10113 case ScopeIterator::ScopeTypeLocal:
10114 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010115 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010116 break;
10117 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010118 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010119 // Return the with object.
10120 return Handle<JSObject>(CurrentContext()->extension());
10121 break;
10122 case ScopeIterator::ScopeTypeClosure:
10123 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010124 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010125 break;
10126 }
10127 UNREACHABLE();
10128 return Handle<JSObject>();
10129 }
10130
10131 // Return the context for this scope. For the local context there might not
10132 // be an actual context.
10133 Handle<Context> CurrentContext() {
10134 if (at_local_ && context_->closure() != *function_) {
10135 return Handle<Context>();
10136 }
10137 return context_;
10138 }
10139
10140#ifdef DEBUG
10141 // Debug print of the content of the current scope.
10142 void DebugPrint() {
10143 switch (Type()) {
10144 case ScopeIterator::ScopeTypeGlobal:
10145 PrintF("Global:\n");
10146 CurrentContext()->Print();
10147 break;
10148
10149 case ScopeIterator::ScopeTypeLocal: {
10150 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010151 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010152 scope_info.Print();
10153 if (!CurrentContext().is_null()) {
10154 CurrentContext()->Print();
10155 if (CurrentContext()->has_extension()) {
10156 Handle<JSObject> extension =
10157 Handle<JSObject>(CurrentContext()->extension());
10158 if (extension->IsJSContextExtensionObject()) {
10159 extension->Print();
10160 }
10161 }
10162 }
10163 break;
10164 }
10165
10166 case ScopeIterator::ScopeTypeWith: {
10167 PrintF("With:\n");
10168 Handle<JSObject> extension =
10169 Handle<JSObject>(CurrentContext()->extension());
10170 extension->Print();
10171 break;
10172 }
10173
ager@chromium.orga1645e22009-09-09 19:27:10 +000010174 case ScopeIterator::ScopeTypeCatch: {
10175 PrintF("Catch:\n");
10176 Handle<JSObject> extension =
10177 Handle<JSObject>(CurrentContext()->extension());
10178 extension->Print();
10179 break;
10180 }
10181
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010182 case ScopeIterator::ScopeTypeClosure: {
10183 PrintF("Closure:\n");
10184 CurrentContext()->Print();
10185 if (CurrentContext()->has_extension()) {
10186 Handle<JSObject> extension =
10187 Handle<JSObject>(CurrentContext()->extension());
10188 if (extension->IsJSContextExtensionObject()) {
10189 extension->Print();
10190 }
10191 }
10192 break;
10193 }
10194
10195 default:
10196 UNREACHABLE();
10197 }
10198 PrintF("\n");
10199 }
10200#endif
10201
10202 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010203 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010204 JavaScriptFrame* frame_;
10205 Handle<JSFunction> function_;
10206 Handle<Context> context_;
10207 bool local_done_;
10208 bool at_local_;
10209
10210 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10211};
10212
10213
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010214static MaybeObject* Runtime_GetScopeCount(RUNTIME_CALLING_CONVENTION) {
10215 RUNTIME_GET_ISOLATE;
10216 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010217 ASSERT(args.length() == 2);
10218
10219 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010220 Object* check;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010221 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args, isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010222 if (!maybe_check->ToObject(&check)) return maybe_check;
10223 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010224 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10225
10226 // Get the frame where the debugging is performed.
10227 StackFrame::Id id = UnwrapFrameId(wrapped_id);
10228 JavaScriptFrameIterator it(id);
10229 JavaScriptFrame* frame = it.frame();
10230
10231 // Count the visible scopes.
10232 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010233 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010234 n++;
10235 }
10236
10237 return Smi::FromInt(n);
10238}
10239
10240
10241static const int kScopeDetailsTypeIndex = 0;
10242static const int kScopeDetailsObjectIndex = 1;
10243static const int kScopeDetailsSize = 2;
10244
10245// Return an array with scope details
10246// args[0]: number: break id
10247// args[1]: number: frame index
10248// args[2]: number: scope index
10249//
10250// The array returned contains the following information:
10251// 0: Scope type
10252// 1: Scope object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010253static MaybeObject* Runtime_GetScopeDetails(RUNTIME_CALLING_CONVENTION) {
10254 RUNTIME_GET_ISOLATE;
10255 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010256 ASSERT(args.length() == 3);
10257
10258 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010259 Object* check;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010260 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args, isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010261 if (!maybe_check->ToObject(&check)) return maybe_check;
10262 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010263 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10264 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10265
10266 // Get the frame where the debugging is performed.
10267 StackFrame::Id id = UnwrapFrameId(wrapped_id);
10268 JavaScriptFrameIterator frame_it(id);
10269 JavaScriptFrame* frame = frame_it.frame();
10270
10271 // Find the requested scope.
10272 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010273 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010274 for (; !it.Done() && n < index; it.Next()) {
10275 n++;
10276 }
10277 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010278 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010279 }
10280
10281 // Calculate the size of the result.
10282 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010283 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010284
10285 // Fill in scope details.
10286 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010287 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010288 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010289 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010290
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010291 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010292}
10293
10294
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010295static MaybeObject* Runtime_DebugPrintScopes(RUNTIME_CALLING_CONVENTION) {
10296 RUNTIME_GET_ISOLATE;
10297 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010298 ASSERT(args.length() == 0);
10299
10300#ifdef DEBUG
10301 // Print the scopes for the top frame.
10302 StackFrameLocator locator;
10303 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010304 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010305 it.DebugPrint();
10306 }
10307#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010308 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010309}
10310
10311
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010312static MaybeObject* Runtime_GetThreadCount(RUNTIME_CALLING_CONVENTION) {
10313 RUNTIME_GET_ISOLATE;
10314 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010315 ASSERT(args.length() == 1);
10316
10317 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010318 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010319 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args, isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010320 if (!maybe_result->ToObject(&result)) return maybe_result;
10321 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010322
10323 // Count all archived V8 threads.
10324 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010325 for (ThreadState* thread =
10326 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010327 thread != NULL;
10328 thread = thread->Next()) {
10329 n++;
10330 }
10331
10332 // Total number of threads is current thread and archived threads.
10333 return Smi::FromInt(n + 1);
10334}
10335
10336
10337static const int kThreadDetailsCurrentThreadIndex = 0;
10338static const int kThreadDetailsThreadIdIndex = 1;
10339static const int kThreadDetailsSize = 2;
10340
10341// Return an array with thread details
10342// args[0]: number: break id
10343// args[1]: number: thread index
10344//
10345// The array returned contains the following information:
10346// 0: Is current thread?
10347// 1: Thread id
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010348static MaybeObject* Runtime_GetThreadDetails(RUNTIME_CALLING_CONVENTION) {
10349 RUNTIME_GET_ISOLATE;
10350 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010351 ASSERT(args.length() == 2);
10352
10353 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010354 Object* check;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010355 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args, isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010356 if (!maybe_check->ToObject(&check)) return maybe_check;
10357 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010358 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10359
10360 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010361 Handle<FixedArray> details =
10362 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010363
10364 // Thread index 0 is current thread.
10365 if (index == 0) {
10366 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010367 details->set(kThreadDetailsCurrentThreadIndex,
10368 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010369 details->set(kThreadDetailsThreadIdIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010370 Smi::FromInt(
10371 isolate->thread_manager()->CurrentId()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010372 } else {
10373 // Find the thread with the requested index.
10374 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010375 ThreadState* thread =
10376 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010377 while (index != n && thread != NULL) {
10378 thread = thread->Next();
10379 n++;
10380 }
10381 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010382 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010383 }
10384
10385 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010386 details->set(kThreadDetailsCurrentThreadIndex,
10387 isolate->heap()->false_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010388 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
10389 }
10390
10391 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010392 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010393}
10394
10395
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010396// Sets the disable break state
10397// args[0]: disable break state
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010398static MaybeObject* Runtime_SetDisableBreak(RUNTIME_CALLING_CONVENTION) {
10399 RUNTIME_GET_ISOLATE;
10400 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010401 ASSERT(args.length() == 1);
10402 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010403 isolate->debug()->set_disable_break(disable_break);
10404 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010405}
10406
10407
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010408static MaybeObject* Runtime_GetBreakLocations(RUNTIME_CALLING_CONVENTION) {
10409 RUNTIME_GET_ISOLATE;
10410 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010411 ASSERT(args.length() == 1);
10412
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010413 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10414 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010415 // Find the number of break points
10416 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010417 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010418 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010419 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010420 Handle<FixedArray>::cast(break_locations));
10421}
10422
10423
10424// Set a break point in a function
10425// args[0]: function
10426// args[1]: number: break source position (within the function source)
10427// args[2]: number: break point object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010428static MaybeObject* Runtime_SetFunctionBreakPoint(RUNTIME_CALLING_CONVENTION) {
10429 RUNTIME_GET_ISOLATE;
10430 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010431 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010432 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10433 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010434 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10435 RUNTIME_ASSERT(source_position >= 0);
10436 Handle<Object> break_point_object_arg = args.at<Object>(2);
10437
10438 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010439 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10440 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010441
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010442 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010443}
10444
10445
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010446Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10447 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010448 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010449 // Iterate the heap looking for SharedFunctionInfo generated from the
10450 // script. The inner most SharedFunctionInfo containing the source position
10451 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010452 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010453 // which is found is not compiled it is compiled and the heap is iterated
10454 // again as the compilation might create inner functions from the newly
10455 // compiled function and the actual requested break point might be in one of
10456 // these functions.
10457 bool done = false;
10458 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010459 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010460 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010461 while (!done) {
10462 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010463 for (HeapObject* obj = iterator.next();
10464 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010465 if (obj->IsSharedFunctionInfo()) {
10466 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10467 if (shared->script() == *script) {
10468 // If the SharedFunctionInfo found has the requested script data and
10469 // contains the source position it is a candidate.
10470 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010471 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010472 start_position = shared->start_position();
10473 }
10474 if (start_position <= position &&
10475 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010476 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010477 // candidate this is the new candidate.
10478 if (target.is_null()) {
10479 target_start_position = start_position;
10480 target = shared;
10481 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010482 if (target_start_position == start_position &&
10483 shared->end_position() == target->end_position()) {
10484 // If a top-level function contain only one function
10485 // declartion the source for the top-level and the function is
10486 // the same. In that case prefer the non top-level function.
10487 if (!shared->is_toplevel()) {
10488 target_start_position = start_position;
10489 target = shared;
10490 }
10491 } else if (target_start_position <= start_position &&
10492 shared->end_position() <= target->end_position()) {
10493 // This containment check includes equality as a function inside
10494 // a top-level function can share either start or end position
10495 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010496 target_start_position = start_position;
10497 target = shared;
10498 }
10499 }
10500 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010501 }
10502 }
10503 }
10504
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010505 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010506 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010507 }
10508
10509 // If the candidate found is compiled we are done. NOTE: when lazy
10510 // compilation of inner functions is introduced some additional checking
10511 // needs to be done here to compile inner functions.
10512 done = target->is_compiled();
10513 if (!done) {
10514 // If the candidate is not compiled compile it to reveal any inner
10515 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010516 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010517 }
10518 }
10519
10520 return *target;
10521}
10522
10523
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010524// Changes the state of a break point in a script and returns source position
10525// where break point was set. NOTE: Regarding performance see the NOTE for
10526// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010527// args[0]: script to set break point in
10528// args[1]: number: break source position (within the script source)
10529// args[2]: number: break point object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010530static MaybeObject* Runtime_SetScriptBreakPoint(RUNTIME_CALLING_CONVENTION) {
10531 RUNTIME_GET_ISOLATE;
10532 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010533 ASSERT(args.length() == 3);
10534 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10535 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10536 RUNTIME_ASSERT(source_position >= 0);
10537 Handle<Object> break_point_object_arg = args.at<Object>(2);
10538
10539 // Get the script from the script wrapper.
10540 RUNTIME_ASSERT(wrapper->value()->IsScript());
10541 Handle<Script> script(Script::cast(wrapper->value()));
10542
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010543 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010544 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010545 if (!result->IsUndefined()) {
10546 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10547 // Find position within function. The script position might be before the
10548 // source position of the first function.
10549 int position;
10550 if (shared->start_position() > source_position) {
10551 position = 0;
10552 } else {
10553 position = source_position - shared->start_position();
10554 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010555 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010556 position += shared->start_position();
10557 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010558 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010559 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010560}
10561
10562
10563// Clear a break point
10564// args[0]: number: break point object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010565static MaybeObject* Runtime_ClearBreakPoint(RUNTIME_CALLING_CONVENTION) {
10566 RUNTIME_GET_ISOLATE;
10567 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010568 ASSERT(args.length() == 1);
10569 Handle<Object> break_point_object_arg = args.at<Object>(0);
10570
10571 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010572 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010573
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010574 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010575}
10576
10577
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010578// Change the state of break on exceptions.
10579// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10580// args[1]: Boolean indicating on/off.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010581static MaybeObject* Runtime_ChangeBreakOnException(RUNTIME_CALLING_CONVENTION) {
10582 RUNTIME_GET_ISOLATE;
10583 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010584 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010585 RUNTIME_ASSERT(args[0]->IsNumber());
10586 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010587
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010588 // If the number doesn't match an enum value, the ChangeBreakOnException
10589 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010590 ExceptionBreakType type =
10591 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010592 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010593 isolate->debug()->ChangeBreakOnException(type, enable);
10594 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010595}
10596
10597
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010598// Returns the state of break on exceptions
10599// args[0]: boolean indicating uncaught exceptions
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010600static MaybeObject* Runtime_IsBreakOnException(RUNTIME_CALLING_CONVENTION) {
10601 RUNTIME_GET_ISOLATE;
10602 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010603 ASSERT(args.length() == 1);
10604 RUNTIME_ASSERT(args[0]->IsNumber());
10605
10606 ExceptionBreakType type =
10607 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010608 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010609 return Smi::FromInt(result);
10610}
10611
10612
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010613// Prepare for stepping
10614// args[0]: break id for checking execution state
10615// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010616// args[2]: number of times to perform the step, for step out it is the number
10617// of frames to step down.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010618static MaybeObject* Runtime_PrepareStep(RUNTIME_CALLING_CONVENTION) {
10619 RUNTIME_GET_ISOLATE;
10620 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010621 ASSERT(args.length() == 3);
10622 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010623 Object* check;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010624 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args, isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010625 if (!maybe_check->ToObject(&check)) return maybe_check;
10626 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010627 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010628 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010629 }
10630
10631 // Get the step action and check validity.
10632 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10633 if (step_action != StepIn &&
10634 step_action != StepNext &&
10635 step_action != StepOut &&
10636 step_action != StepInMin &&
10637 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010638 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010639 }
10640
10641 // Get the number of steps.
10642 int step_count = NumberToInt32(args[2]);
10643 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010644 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010645 }
10646
ager@chromium.orga1645e22009-09-09 19:27:10 +000010647 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010648 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010649
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010650 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010651 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10652 step_count);
10653 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010654}
10655
10656
10657// Clear all stepping set by PrepareStep.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010658static MaybeObject* Runtime_ClearStepping(RUNTIME_CALLING_CONVENTION) {
10659 RUNTIME_GET_ISOLATE;
10660 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010661 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010662 isolate->debug()->ClearStepping();
10663 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010664}
10665
10666
10667// Creates a copy of the with context chain. The copy of the context chain is
10668// is linked to the function context supplied.
10669static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10670 Handle<Context> function_context) {
10671 // At the bottom of the chain. Return the function context to link to.
10672 if (context_chain->is_function_context()) {
10673 return function_context;
10674 }
10675
10676 // Recursively copy the with contexts.
10677 Handle<Context> previous(context_chain->previous());
10678 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010679 Handle<Context> context = CopyWithContextChain(function_context, previous);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010680 return context->GetIsolate()->factory()->NewWithContext(
10681 context, extension, context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010682}
10683
10684
10685// Helper function to find or create the arguments object for
10686// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010687static Handle<Object> GetArgumentsObject(Isolate* isolate,
10688 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010689 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010690 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010691 const ScopeInfo<>* sinfo,
10692 Handle<Context> function_context) {
10693 // Try to find the value of 'arguments' to pass as parameter. If it is not
10694 // found (that is the debugged function does not reference 'arguments' and
10695 // does not support eval) then create an 'arguments' object.
10696 int index;
10697 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010698 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010699 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010700 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010701 }
10702 }
10703
10704 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010705 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10706 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010707 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010708 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010709 }
10710 }
10711
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010712 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010713 Handle<JSObject> arguments =
10714 isolate->factory()->NewArgumentsObject(function, length);
10715 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010716
10717 AssertNoAllocation no_gc;
10718 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010719 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010720 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010721 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010722 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010723 return arguments;
10724}
10725
10726
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010727static const char kSourceStr[] =
10728 "(function(arguments,__source__){return eval(__source__);})";
10729
10730
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010731// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010732// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010733// extension part has all the parameters and locals of the function on the
10734// stack frame. A function which calls eval with the code to evaluate is then
10735// compiled in this context and called in this context. As this context
10736// replaces the context of the function on the stack frame a new (empty)
10737// function is created as well to be used as the closure for the context.
10738// This function and the context acts as replacements for the function on the
10739// stack frame presenting the same view of the values of parameters and
10740// local variables as if the piece of JavaScript was evaluated at the point
10741// where the function on the stack frame is currently stopped.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010742static MaybeObject* Runtime_DebugEvaluate(RUNTIME_CALLING_CONVENTION) {
10743 RUNTIME_GET_ISOLATE;
10744 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010745
10746 // Check the execution state and decode arguments frame and source to be
10747 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010748 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010749 Object* check_result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010750 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args,
10751 isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010752 if (!maybe_check_result->ToObject(&check_result)) {
10753 return maybe_check_result;
10754 }
10755 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010756 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10757 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010758 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010759 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010760
10761 // Handle the processing of break.
10762 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010763
10764 // Get the frame where the debugging is performed.
10765 StackFrame::Id id = UnwrapFrameId(wrapped_id);
10766 JavaScriptFrameIterator it(id);
10767 JavaScriptFrame* frame = it.frame();
10768 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010769 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010770 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010771
10772 // Traverse the saved contexts chain to find the active context for the
10773 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010774 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010775 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010776 save = save->prev();
10777 }
10778 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010779 SaveContext savex(isolate);
10780 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010781
10782 // Create the (empty) function replacing the function on the stack frame for
10783 // the purpose of evaluating in the context created below. It is important
10784 // that this function does not describe any parameters and local variables
10785 // in the context. If it does then this will cause problems with the lookup
10786 // in Context::Lookup, where context slots for parameters and local variables
10787 // are looked at before the extension object.
10788 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010789 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10790 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010791 go_between->set_context(function->context());
10792#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010793 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010794 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10795 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10796#endif
10797
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010798 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010799 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10800 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010801
10802 // Allocate a new context for the debug evaluation and set the extension
10803 // object build.
10804 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010805 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10806 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010807 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010808 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010809 Handle<Context> frame_context(Context::cast(frame->context()));
10810 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010811 context = CopyWithContextChain(frame_context, context);
10812
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010813 if (additional_context->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010814 context = isolate->factory()->NewWithContext(context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010815 Handle<JSObject>::cast(additional_context), false);
10816 }
10817
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010818 // Wrap the evaluation statement in a new function compiled in the newly
10819 // created context. The function has one parameter which has to be called
10820 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010821 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010822 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010823
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010824 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010825 isolate->factory()->NewStringFromAscii(
10826 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010827
10828 // Currently, the eval code will be executed in non-strict mode,
10829 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010830 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010831 Compiler::CompileEval(function_source,
10832 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010833 context->IsGlobalContext(),
10834 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010835 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010836 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010837 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010838
10839 // Invoke the result of the compilation to get the evaluation function.
10840 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010841 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010842 Handle<Object> evaluation_function =
10843 Execution::Call(compiled_function, receiver, 0, NULL,
10844 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010845 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010846
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010847 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
10848 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010849 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010850
10851 // Invoke the evaluation function and return the result.
10852 const int argc = 2;
10853 Object** argv[argc] = { arguments.location(),
10854 Handle<Object>::cast(source).location() };
10855 Handle<Object> result =
10856 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10857 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010858 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010859
10860 // Skip the global proxy as it has no properties and always delegates to the
10861 // real global object.
10862 if (result->IsJSGlobalProxy()) {
10863 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10864 }
10865
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010866 return *result;
10867}
10868
10869
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010870static MaybeObject* Runtime_DebugEvaluateGlobal(RUNTIME_CALLING_CONVENTION) {
10871 RUNTIME_GET_ISOLATE;
10872 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873
10874 // Check the execution state and decode arguments frame and source to be
10875 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010876 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010877 Object* check_result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010878 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args,
10879 isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010880 if (!maybe_check_result->ToObject(&check_result)) {
10881 return maybe_check_result;
10882 }
10883 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010884 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010885 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010886 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010887
10888 // Handle the processing of break.
10889 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010890
10891 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010892 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010893 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010894 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010895 top = top->prev();
10896 }
10897 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010898 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010899 }
10900
10901 // Get the global context now set to the top context from before the
10902 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010903 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010904
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010905 bool is_global = true;
10906
10907 if (additional_context->IsJSObject()) {
10908 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010909 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
10910 isolate->factory()->empty_string(),
10911 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010912 go_between->set_context(*context);
10913 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010914 isolate->factory()->NewFunctionContext(
10915 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010916 context->set_extension(JSObject::cast(*additional_context));
10917 is_global = false;
10918 }
10919
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010920 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010921 // Currently, the eval code will be executed in non-strict mode,
10922 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010923 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010924 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010925 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010926 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010927 Handle<JSFunction>(
10928 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
10929 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010930
10931 // Invoke the result of the compilation to get the evaluation function.
10932 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010933 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010934 Handle<Object> result =
10935 Execution::Call(compiled_function, receiver, 0, NULL,
10936 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010937 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010938 return *result;
10939}
10940
10941
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010942static MaybeObject* Runtime_DebugGetLoadedScripts(RUNTIME_CALLING_CONVENTION) {
10943 RUNTIME_GET_ISOLATE;
10944 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010945 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010946
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010947 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010948 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010949
10950 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010951 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010952 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10953 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10954 // because using
10955 // instances->set(i, *GetScriptWrapper(script))
10956 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10957 // already have deferenced the instances handle.
10958 Handle<JSValue> wrapper = GetScriptWrapper(script);
10959 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010960 }
10961
10962 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010963 Handle<JSObject> result =
10964 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010965 Handle<JSArray>::cast(result)->SetContent(*instances);
10966 return *result;
10967}
10968
10969
10970// Helper function used by Runtime_DebugReferencedBy below.
10971static int DebugReferencedBy(JSObject* target,
10972 Object* instance_filter, int max_references,
10973 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010974 JSFunction* arguments_function) {
10975 NoHandleAllocation ha;
10976 AssertNoAllocation no_alloc;
10977
10978 // Iterate the heap.
10979 int count = 0;
10980 JSObject* last = NULL;
10981 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010982 HeapObject* heap_obj = NULL;
10983 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010984 (max_references == 0 || count < max_references)) {
10985 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010986 if (heap_obj->IsJSObject()) {
10987 // Skip context extension objects and argument arrays as these are
10988 // checked in the context of functions using them.
10989 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010990 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010991 obj->map()->constructor() == arguments_function) {
10992 continue;
10993 }
10994
10995 // Check if the JS object has a reference to the object looked for.
10996 if (obj->ReferencesObject(target)) {
10997 // Check instance filter if supplied. This is normally used to avoid
10998 // references from mirror objects (see Runtime_IsInPrototypeChain).
10999 if (!instance_filter->IsUndefined()) {
11000 Object* V = obj;
11001 while (true) {
11002 Object* prototype = V->GetPrototype();
11003 if (prototype->IsNull()) {
11004 break;
11005 }
11006 if (instance_filter == prototype) {
11007 obj = NULL; // Don't add this object.
11008 break;
11009 }
11010 V = prototype;
11011 }
11012 }
11013
11014 if (obj != NULL) {
11015 // Valid reference found add to instance array if supplied an update
11016 // count.
11017 if (instances != NULL && count < instances_size) {
11018 instances->set(count, obj);
11019 }
11020 last = obj;
11021 count++;
11022 }
11023 }
11024 }
11025 }
11026
11027 // Check for circular reference only. This can happen when the object is only
11028 // referenced from mirrors and has a circular reference in which case the
11029 // object is not really alive and would have been garbage collected if not
11030 // referenced from the mirror.
11031 if (count == 1 && last == target) {
11032 count = 0;
11033 }
11034
11035 // Return the number of referencing objects found.
11036 return count;
11037}
11038
11039
11040// Scan the heap for objects with direct references to an object
11041// args[0]: the object to find references to
11042// args[1]: constructor function for instances to exclude (Mirror)
11043// args[2]: the the maximum number of objects to return
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011044static MaybeObject* Runtime_DebugReferencedBy(RUNTIME_CALLING_CONVENTION) {
11045 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011046 ASSERT(args.length() == 3);
11047
11048 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011049 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011050
11051 // Check parameters.
11052 CONVERT_CHECKED(JSObject, target, args[0]);
11053 Object* instance_filter = args[1];
11054 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11055 instance_filter->IsJSObject());
11056 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11057 RUNTIME_ASSERT(max_references >= 0);
11058
11059 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011060 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011061 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011062 JSFunction* arguments_function =
11063 JSFunction::cast(arguments_boilerplate->map()->constructor());
11064
11065 // Get the number of referencing objects.
11066 int count;
11067 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011068 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011069
11070 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011071 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011072 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011073 if (!maybe_object->ToObject(&object)) return maybe_object;
11074 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011075 FixedArray* instances = FixedArray::cast(object);
11076
11077 // Fill the referencing objects.
11078 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011079 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011080
11081 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011082 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011083 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11084 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011085 if (!maybe_result->ToObject(&result)) return maybe_result;
11086 }
11087 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011088 return result;
11089}
11090
11091
11092// Helper function used by Runtime_DebugConstructedBy below.
11093static int DebugConstructedBy(JSFunction* constructor, int max_references,
11094 FixedArray* instances, int instances_size) {
11095 AssertNoAllocation no_alloc;
11096
11097 // Iterate the heap.
11098 int count = 0;
11099 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011100 HeapObject* heap_obj = NULL;
11101 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011102 (max_references == 0 || count < max_references)) {
11103 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011104 if (heap_obj->IsJSObject()) {
11105 JSObject* obj = JSObject::cast(heap_obj);
11106 if (obj->map()->constructor() == constructor) {
11107 // Valid reference found add to instance array if supplied an update
11108 // count.
11109 if (instances != NULL && count < instances_size) {
11110 instances->set(count, obj);
11111 }
11112 count++;
11113 }
11114 }
11115 }
11116
11117 // Return the number of referencing objects found.
11118 return count;
11119}
11120
11121
11122// Scan the heap for objects constructed by a specific function.
11123// args[0]: the constructor to find instances of
11124// args[1]: the the maximum number of objects to return
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011125static MaybeObject* Runtime_DebugConstructedBy(RUNTIME_CALLING_CONVENTION) {
11126 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011127 ASSERT(args.length() == 2);
11128
11129 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011130 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011131
11132 // Check parameters.
11133 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11134 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11135 RUNTIME_ASSERT(max_references >= 0);
11136
11137 // Get the number of referencing objects.
11138 int count;
11139 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11140
11141 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011142 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011143 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011144 if (!maybe_object->ToObject(&object)) return maybe_object;
11145 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011146 FixedArray* instances = FixedArray::cast(object);
11147
11148 // Fill the referencing objects.
11149 count = DebugConstructedBy(constructor, max_references, instances, count);
11150
11151 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011152 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011153 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11154 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011155 if (!maybe_result->ToObject(&result)) return maybe_result;
11156 }
11157 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011158 return result;
11159}
11160
11161
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011162// Find the effective prototype object as returned by __proto__.
11163// args[0]: the object to find the prototype for.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011164static MaybeObject* Runtime_DebugGetPrototype(RUNTIME_CALLING_CONVENTION) {
11165 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011166 ASSERT(args.length() == 1);
11167
11168 CONVERT_CHECKED(JSObject, obj, args[0]);
11169
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011170 // Use the __proto__ accessor.
11171 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011172}
11173
11174
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011175static MaybeObject* Runtime_SystemBreak(RUNTIME_CALLING_CONVENTION) {
11176 RUNTIME_GET_ISOLATE;
mads.s.ager31e71382008-08-13 09:32:07 +000011177 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011178 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011179 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011180}
11181
11182
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011183static MaybeObject* Runtime_DebugDisassembleFunction(
11184 RUNTIME_CALLING_CONVENTION) {
11185 RUNTIME_GET_ISOLATE;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011186#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011187 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011188 ASSERT(args.length() == 1);
11189 // Get the function and make sure it is compiled.
11190 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011191 Handle<SharedFunctionInfo> shared(func->shared());
11192 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011193 return Failure::Exception();
11194 }
11195 func->code()->PrintLn();
11196#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011197 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011198}
ager@chromium.org9085a012009-05-11 19:22:57 +000011199
11200
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011201static MaybeObject* Runtime_DebugDisassembleConstructor(
11202 RUNTIME_CALLING_CONVENTION) {
11203 RUNTIME_GET_ISOLATE;
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011204#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011205 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011206 ASSERT(args.length() == 1);
11207 // Get the function and make sure it is compiled.
11208 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011209 Handle<SharedFunctionInfo> shared(func->shared());
11210 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011211 return Failure::Exception();
11212 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011213 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011214#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011215 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011216}
11217
11218
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011219static MaybeObject* Runtime_FunctionGetInferredName(
11220 RUNTIME_CALLING_CONVENTION) {
11221 RUNTIME_GET_ISOLATE;
ager@chromium.org9085a012009-05-11 19:22:57 +000011222 NoHandleAllocation ha;
11223 ASSERT(args.length() == 1);
11224
11225 CONVERT_CHECKED(JSFunction, f, args[0]);
11226 return f->shared()->inferred_name();
11227}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011228
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011229
11230static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011231 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011232 AssertNoAllocation no_allocations;
11233
11234 int counter = 0;
11235 int buffer_size = buffer->length();
11236 HeapIterator iterator;
11237 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11238 ASSERT(obj != NULL);
11239 if (!obj->IsSharedFunctionInfo()) {
11240 continue;
11241 }
11242 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11243 if (shared->script() != script) {
11244 continue;
11245 }
11246 if (counter < buffer_size) {
11247 buffer->set(counter, shared);
11248 }
11249 counter++;
11250 }
11251 return counter;
11252}
11253
11254// For a script finds all SharedFunctionInfo's in the heap that points
11255// to this script. Returns JSArray of SharedFunctionInfo wrapped
11256// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011257static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011258 RUNTIME_CALLING_CONVENTION) {
11259 RUNTIME_GET_ISOLATE;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011260 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011261 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011262 CONVERT_CHECKED(JSValue, script_value, args[0]);
11263
11264 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11265
11266 const int kBufferSize = 32;
11267
11268 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011269 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011270 int number = FindSharedFunctionInfosForScript(*script, *array);
11271 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011272 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011273 FindSharedFunctionInfosForScript(*script, *array);
11274 }
11275
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011276 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011277 result->set_length(Smi::FromInt(number));
11278
11279 LiveEdit::WrapSharedFunctionInfos(result);
11280
11281 return *result;
11282}
11283
11284// For a script calculates compilation information about all its functions.
11285// The script source is explicitly specified by the second argument.
11286// The source of the actual script is not used, however it is important that
11287// all generated code keeps references to this particular instance of script.
11288// Returns a JSArray of compilation infos. The array is ordered so that
11289// each function with all its descendant is always stored in a continues range
11290// with the function itself going first. The root function is a script function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011291static MaybeObject* Runtime_LiveEditGatherCompileInfo(
11292 RUNTIME_CALLING_CONVENTION) {
11293 RUNTIME_GET_ISOLATE;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011294 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011295 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011296 CONVERT_CHECKED(JSValue, script, args[0]);
11297 CONVERT_ARG_CHECKED(String, source, 1);
11298 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11299
11300 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11301
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011302 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011303 return Failure::Exception();
11304 }
11305
11306 return result;
11307}
11308
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011309// Changes the source of the script to a new_source.
11310// If old_script_name is provided (i.e. is a String), also creates a copy of
11311// the script with its original source and sends notification to debugger.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011312static MaybeObject* Runtime_LiveEditReplaceScript(RUNTIME_CALLING_CONVENTION) {
11313 RUNTIME_GET_ISOLATE;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011314 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011315 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011316 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11317 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011318 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011319
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011320 CONVERT_CHECKED(Script, original_script_pointer,
11321 original_script_value->value());
11322 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011323
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011324 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11325 new_source,
11326 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011327
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011328 if (old_script->IsScript()) {
11329 Handle<Script> script_handle(Script::cast(old_script));
11330 return *(GetScriptWrapper(script_handle));
11331 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011332 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011333 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011334}
11335
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011336
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011337static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(
11338 RUNTIME_CALLING_CONVENTION) {
11339 RUNTIME_GET_ISOLATE;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011340 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011341 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011342 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11343 return LiveEdit::FunctionSourceUpdated(shared_info);
11344}
11345
11346
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011347// Replaces code of SharedFunctionInfo with a new one.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011348static MaybeObject* Runtime_LiveEditReplaceFunctionCode(
11349 RUNTIME_CALLING_CONVENTION) {
11350 RUNTIME_GET_ISOLATE;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011351 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011352 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011353 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11354 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11355
ager@chromium.orgac091b72010-05-05 07:34:42 +000011356 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011357}
11358
11359// Connects SharedFunctionInfo to another script.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011360static MaybeObject* Runtime_LiveEditFunctionSetScript(
11361 RUNTIME_CALLING_CONVENTION) {
11362 RUNTIME_GET_ISOLATE;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011363 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011364 HandleScope scope(isolate);
11365 Handle<Object> function_object(args[0], isolate);
11366 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011367
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011368 if (function_object->IsJSValue()) {
11369 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11370 if (script_object->IsJSValue()) {
11371 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011372 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011373 }
11374
11375 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11376 } else {
11377 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11378 // and we check it in this function.
11379 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011380
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011381 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011382}
11383
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011384
11385// In a code of a parent function replaces original function as embedded object
11386// with a substitution one.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011387static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(
11388 RUNTIME_CALLING_CONVENTION) {
11389 RUNTIME_GET_ISOLATE;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011390 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011391 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011392
11393 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11394 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11395 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11396
11397 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11398 subst_wrapper);
11399
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011400 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011401}
11402
11403
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011404// Updates positions of a shared function info (first parameter) according
11405// to script source change. Text change is described in second parameter as
11406// array of groups of 3 numbers:
11407// (change_begin, change_end, change_end_new_position).
11408// Each group describes a change in text; groups are sorted by change_begin.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011409static MaybeObject* Runtime_LiveEditPatchFunctionPositions(
11410 RUNTIME_CALLING_CONVENTION) {
11411 RUNTIME_GET_ISOLATE;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011412 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011413 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011414 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11415 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11416
ager@chromium.orgac091b72010-05-05 07:34:42 +000011417 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011418}
11419
11420
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011421// For array of SharedFunctionInfo's (each wrapped in JSValue)
11422// checks that none of them have activations on stacks (of any thread).
11423// Returns array of the same length with corresponding results of
11424// LiveEdit::FunctionPatchabilityStatus type.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011425static MaybeObject* Runtime_LiveEditCheckAndDropActivations(
11426 RUNTIME_CALLING_CONVENTION) {
11427 RUNTIME_GET_ISOLATE;
ager@chromium.org357bf652010-04-12 11:30:10 +000011428 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011429 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011430 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011431 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011432
ager@chromium.org357bf652010-04-12 11:30:10 +000011433 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011434}
11435
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011436// Compares 2 strings line-by-line, then token-wise and returns diff in form
11437// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11438// of diff chunks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011439static MaybeObject* Runtime_LiveEditCompareStrings(RUNTIME_CALLING_CONVENTION) {
11440 RUNTIME_GET_ISOLATE;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011441 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011442 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011443 CONVERT_ARG_CHECKED(String, s1, 0);
11444 CONVERT_ARG_CHECKED(String, s2, 1);
11445
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011446 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011447}
11448
11449
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011450// A testing entry. Returns statement position which is the closest to
11451// source_position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011452static MaybeObject* Runtime_GetFunctionCodePositionFromSource(
11453 RUNTIME_CALLING_CONVENTION) {
11454 RUNTIME_GET_ISOLATE;
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011455 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011456 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011457 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11458 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11459
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011460 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011461
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011462 if (code->kind() != Code::FUNCTION &&
11463 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011464 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011465 }
11466
11467 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011468 int closest_pc = 0;
11469 int distance = kMaxInt;
11470 while (!it.done()) {
11471 int statement_position = static_cast<int>(it.rinfo()->data());
11472 // Check if this break point is closer that what was previously found.
11473 if (source_position <= statement_position &&
11474 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011475 closest_pc =
11476 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011477 distance = statement_position - source_position;
11478 // Check whether we can't get any closer.
11479 if (distance == 0) break;
11480 }
11481 it.next();
11482 }
11483
11484 return Smi::FromInt(closest_pc);
11485}
11486
11487
ager@chromium.org357bf652010-04-12 11:30:10 +000011488// Calls specified function with or without entering the debugger.
11489// This is used in unit tests to run code as if debugger is entered or simply
11490// to have a stack with C++ frame in the middle.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011491static MaybeObject* Runtime_ExecuteInDebugContext(RUNTIME_CALLING_CONVENTION) {
11492 RUNTIME_GET_ISOLATE;
ager@chromium.org357bf652010-04-12 11:30:10 +000011493 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011494 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011495 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11496 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11497
11498 Handle<Object> result;
11499 bool pending_exception;
11500 {
11501 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011502 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011503 &pending_exception);
11504 } else {
11505 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011506 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011507 &pending_exception);
11508 }
11509 }
11510 if (!pending_exception) {
11511 return *result;
11512 } else {
11513 return Failure::Exception();
11514 }
11515}
11516
11517
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011518// Sets a v8 flag.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011519static MaybeObject* Runtime_SetFlags(RUNTIME_CALLING_CONVENTION) {
11520 RUNTIME_GET_ISOLATE;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011521 CONVERT_CHECKED(String, arg, args[0]);
11522 SmartPointer<char> flags =
11523 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11524 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011525 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011526}
11527
11528
11529// Performs a GC.
11530// Presently, it only does a full GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011531static MaybeObject* Runtime_CollectGarbage(RUNTIME_CALLING_CONVENTION) {
11532 RUNTIME_GET_ISOLATE;
11533 isolate->heap()->CollectAllGarbage(true);
11534 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011535}
11536
11537
11538// Gets the current heap usage.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011539static MaybeObject* Runtime_GetHeapUsage(RUNTIME_CALLING_CONVENTION) {
11540 RUNTIME_GET_ISOLATE;
11541 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011542 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011543 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011544 }
11545 return Smi::FromInt(usage);
11546}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011547
11548
11549// Captures a live object list from the present heap.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011550static MaybeObject* Runtime_HasLOLEnabled(RUNTIME_CALLING_CONVENTION) {
11551 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011552#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011553 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011554#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011555 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011556#endif
11557}
11558
11559
11560// Captures a live object list from the present heap.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011561static MaybeObject* Runtime_CaptureLOL(RUNTIME_CALLING_CONVENTION) {
11562 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011563#ifdef LIVE_OBJECT_LIST
11564 return LiveObjectList::Capture();
11565#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011566 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011567#endif
11568}
11569
11570
11571// Deletes the specified live object list.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011572static MaybeObject* Runtime_DeleteLOL(RUNTIME_CALLING_CONVENTION) {
11573 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011574#ifdef LIVE_OBJECT_LIST
11575 CONVERT_SMI_CHECKED(id, args[0]);
11576 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011577 return success ? isolate->heap()->true_value() :
11578 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011579#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011580 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011581#endif
11582}
11583
11584
11585// Generates the response to a debugger request for a dump of the objects
11586// contained in the difference between the captured live object lists
11587// specified by id1 and id2.
11588// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11589// dumped.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011590static MaybeObject* Runtime_DumpLOL(RUNTIME_CALLING_CONVENTION) {
11591 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011592#ifdef LIVE_OBJECT_LIST
11593 HandleScope scope;
11594 CONVERT_SMI_CHECKED(id1, args[0]);
11595 CONVERT_SMI_CHECKED(id2, args[1]);
11596 CONVERT_SMI_CHECKED(start, args[2]);
11597 CONVERT_SMI_CHECKED(count, args[3]);
11598 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11599 EnterDebugger enter_debugger;
11600 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11601#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011602 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011603#endif
11604}
11605
11606
11607// Gets the specified object as requested by the debugger.
11608// This is only used for obj ids shown in live object lists.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011609static MaybeObject* Runtime_GetLOLObj(RUNTIME_CALLING_CONVENTION) {
11610 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011611#ifdef LIVE_OBJECT_LIST
11612 CONVERT_SMI_CHECKED(obj_id, args[0]);
11613 Object* result = LiveObjectList::GetObj(obj_id);
11614 return result;
11615#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011616 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011617#endif
11618}
11619
11620
11621// Gets the obj id for the specified address if valid.
11622// This is only used for obj ids shown in live object lists.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011623static MaybeObject* Runtime_GetLOLObjId(RUNTIME_CALLING_CONVENTION) {
11624 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011625#ifdef LIVE_OBJECT_LIST
11626 HandleScope scope;
11627 CONVERT_ARG_CHECKED(String, address, 0);
11628 Object* result = LiveObjectList::GetObjId(address);
11629 return result;
11630#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011631 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011632#endif
11633}
11634
11635
11636// Gets the retainers that references the specified object alive.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011637static MaybeObject* Runtime_GetLOLObjRetainers(RUNTIME_CALLING_CONVENTION) {
11638 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011639#ifdef LIVE_OBJECT_LIST
11640 HandleScope scope;
11641 CONVERT_SMI_CHECKED(obj_id, args[0]);
11642 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11643 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11644 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11645 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11646 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11647
11648 Handle<JSObject> instance_filter;
11649 if (args[1]->IsJSObject()) {
11650 instance_filter = args.at<JSObject>(1);
11651 }
11652 bool verbose = false;
11653 if (args[2]->IsBoolean()) {
11654 verbose = args[2]->IsTrue();
11655 }
11656 int start = 0;
11657 if (args[3]->IsSmi()) {
11658 start = Smi::cast(args[3])->value();
11659 }
11660 int limit = Smi::kMaxValue;
11661 if (args[4]->IsSmi()) {
11662 limit = Smi::cast(args[4])->value();
11663 }
11664
11665 return LiveObjectList::GetObjRetainers(obj_id,
11666 instance_filter,
11667 verbose,
11668 start,
11669 limit,
11670 filter_obj);
11671#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011672 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011673#endif
11674}
11675
11676
11677// Gets the reference path between 2 objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011678static MaybeObject* Runtime_GetLOLPath(RUNTIME_CALLING_CONVENTION) {
11679 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011680#ifdef LIVE_OBJECT_LIST
11681 HandleScope scope;
11682 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11683 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11684 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11685
11686 Handle<JSObject> instance_filter;
11687 if (args[2]->IsJSObject()) {
11688 instance_filter = args.at<JSObject>(2);
11689 }
11690
11691 Object* result =
11692 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11693 return result;
11694#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011695 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011696#endif
11697}
11698
11699
11700// Generates the response to a debugger request for a list of all
11701// previously captured live object lists.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011702static MaybeObject* Runtime_InfoLOL(RUNTIME_CALLING_CONVENTION) {
11703 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011704#ifdef LIVE_OBJECT_LIST
11705 CONVERT_SMI_CHECKED(start, args[0]);
11706 CONVERT_SMI_CHECKED(count, args[1]);
11707 return LiveObjectList::Info(start, count);
11708#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011709 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011710#endif
11711}
11712
11713
11714// Gets a dump of the specified object as requested by the debugger.
11715// This is only used for obj ids shown in live object lists.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011716static MaybeObject* Runtime_PrintLOLObj(RUNTIME_CALLING_CONVENTION) {
11717 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011718#ifdef LIVE_OBJECT_LIST
11719 HandleScope scope;
11720 CONVERT_SMI_CHECKED(obj_id, args[0]);
11721 Object* result = LiveObjectList::PrintObj(obj_id);
11722 return result;
11723#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011724 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011725#endif
11726}
11727
11728
11729// Resets and releases all previously captured live object lists.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011730static MaybeObject* Runtime_ResetLOL(RUNTIME_CALLING_CONVENTION) {
11731 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011732#ifdef LIVE_OBJECT_LIST
11733 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011734 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011735#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011736 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011737#endif
11738}
11739
11740
11741// Generates the response to a debugger request for a summary of the types
11742// of objects in the difference between the captured live object lists
11743// specified by id1 and id2.
11744// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11745// summarized.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011746static MaybeObject* Runtime_SummarizeLOL(RUNTIME_CALLING_CONVENTION) {
11747 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011748#ifdef LIVE_OBJECT_LIST
11749 HandleScope scope;
11750 CONVERT_SMI_CHECKED(id1, args[0]);
11751 CONVERT_SMI_CHECKED(id2, args[1]);
11752 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11753
11754 EnterDebugger enter_debugger;
11755 return LiveObjectList::Summarize(id1, id2, filter_obj);
11756#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011757 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011758#endif
11759}
11760
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011761#endif // ENABLE_DEBUGGER_SUPPORT
11762
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011763
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011764#ifdef ENABLE_LOGGING_AND_PROFILING
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011765static MaybeObject* Runtime_ProfilerResume(RUNTIME_CALLING_CONVENTION) {
11766 RUNTIME_GET_ISOLATE;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011767 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011768 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011769
11770 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011771 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11772 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011773 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011774}
11775
11776
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011777static MaybeObject* Runtime_ProfilerPause(RUNTIME_CALLING_CONVENTION) {
11778 RUNTIME_GET_ISOLATE;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011779 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011780 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011781
11782 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011783 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11784 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011785 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011786}
11787
11788#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011789
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011790// Finds the script object from the script data. NOTE: This operation uses
11791// heap traversal to find the function generated for the source position
11792// for the requested break point. For lazily compiled functions several heap
11793// traversals might be required rendering this operation as a rather slow
11794// operation. However for setting break points which is normally done through
11795// some kind of user interaction the performance is not crucial.
11796static Handle<Object> Runtime_GetScriptFromScriptName(
11797 Handle<String> script_name) {
11798 // Scan the heap for Script objects to find the script with the requested
11799 // script data.
11800 Handle<Script> script;
11801 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011802 HeapObject* obj = NULL;
11803 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011804 // If a script is found check if it has the script data requested.
11805 if (obj->IsScript()) {
11806 if (Script::cast(obj)->name()->IsString()) {
11807 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11808 script = Handle<Script>(Script::cast(obj));
11809 }
11810 }
11811 }
11812 }
11813
11814 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011815 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011816
11817 // Return the script found.
11818 return GetScriptWrapper(script);
11819}
11820
11821
11822// Get the script object from script data. NOTE: Regarding performance
11823// see the NOTE for GetScriptFromScriptData.
11824// args[0]: script data for the script to find the source for
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011825static MaybeObject* Runtime_GetScript(RUNTIME_CALLING_CONVENTION) {
11826 RUNTIME_GET_ISOLATE;
11827 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011828
11829 ASSERT(args.length() == 1);
11830
11831 CONVERT_CHECKED(String, script_name, args[0]);
11832
11833 // Find the requested script.
11834 Handle<Object> result =
11835 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11836 return *result;
11837}
11838
11839
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011840// Determines whether the given stack frame should be displayed in
11841// a stack trace. The caller is the error constructor that asked
11842// for the stack trace to be collected. The first time a construct
11843// call to this function is encountered it is skipped. The seen_caller
11844// in/out parameter is used to remember if the caller has been seen
11845// yet.
11846static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11847 bool* seen_caller) {
11848 // Only display JS frames.
11849 if (!raw_frame->is_java_script())
11850 return false;
11851 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11852 Object* raw_fun = frame->function();
11853 // Not sure when this can happen but skip it just in case.
11854 if (!raw_fun->IsJSFunction())
11855 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011856 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011857 *seen_caller = true;
11858 return false;
11859 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011860 // Skip all frames until we've seen the caller. Also, skip the most
11861 // obvious builtin calls. Some builtin calls (such as Number.ADD
11862 // which is invoked using 'call') are very difficult to recognize
11863 // so we're leaving them in for now.
11864 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011865}
11866
11867
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011868// Collect the raw data for a stack trace. Returns an array of 4
11869// element segments each containing a receiver, function, code and
11870// native code offset.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011871static MaybeObject* Runtime_CollectStackTrace(RUNTIME_CALLING_CONVENTION) {
11872 RUNTIME_GET_ISOLATE;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011873 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011874 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011875 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11876
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011877 HandleScope scope(isolate);
11878 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011879
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011880 limit = Max(limit, 0); // Ensure that limit is not negative.
11881 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011882 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011883 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011884
11885 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011886 // If the caller parameter is a function we skip frames until we're
11887 // under it before starting to collect.
11888 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011889 int cursor = 0;
11890 int frames_seen = 0;
11891 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011892 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011893 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011894 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011895 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011896 List<FrameSummary> frames(3); // Max 2 levels of inlining.
11897 frame->Summarize(&frames);
11898 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011899 if (cursor + 4 > elements->length()) {
11900 int new_capacity = JSObject::NewElementsCapacity(elements->length());
11901 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011902 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011903 for (int i = 0; i < cursor; i++) {
11904 new_elements->set(i, elements->get(i));
11905 }
11906 elements = new_elements;
11907 }
11908 ASSERT(cursor + 4 <= elements->length());
11909
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011910 Handle<Object> recv = frames[i].receiver();
11911 Handle<JSFunction> fun = frames[i].function();
11912 Handle<Code> code = frames[i].code();
11913 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011914 elements->set(cursor++, *recv);
11915 elements->set(cursor++, *fun);
11916 elements->set(cursor++, *code);
11917 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011918 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011919 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011920 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011921 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011922 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011923 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011924 return *result;
11925}
11926
11927
ager@chromium.org3811b432009-10-28 14:53:37 +000011928// Returns V8 version as a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011929static MaybeObject* Runtime_GetV8Version(RUNTIME_CALLING_CONVENTION) {
11930 RUNTIME_GET_ISOLATE;
ager@chromium.org3811b432009-10-28 14:53:37 +000011931 ASSERT_EQ(args.length(), 0);
11932
11933 NoHandleAllocation ha;
11934
11935 const char* version_string = v8::V8::GetVersion();
11936
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011937 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
11938 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000011939}
11940
11941
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011942static MaybeObject* Runtime_Abort(RUNTIME_CALLING_CONVENTION) {
11943 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011944 ASSERT(args.length() == 2);
11945 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11946 Smi::cast(args[1])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011947 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011948 OS::Abort();
11949 UNREACHABLE();
11950 return NULL;
11951}
11952
11953
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011954static MaybeObject* Runtime_GetFromCache(RUNTIME_CALLING_CONVENTION) {
11955 RUNTIME_GET_ISOLATE;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011956 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011957 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011958 Object* key = args[1];
11959
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011960 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011961 Object* o = cache->get(finger_index);
11962 if (o == key) {
11963 // The fastest case: hit the same place again.
11964 return cache->get(finger_index + 1);
11965 }
11966
11967 for (int i = finger_index - 2;
11968 i >= JSFunctionResultCache::kEntriesIndex;
11969 i -= 2) {
11970 o = cache->get(i);
11971 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011972 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011973 return cache->get(i + 1);
11974 }
11975 }
11976
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011977 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011978 ASSERT(size <= cache->length());
11979
11980 for (int i = size - 2; i > finger_index; i -= 2) {
11981 o = cache->get(i);
11982 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011983 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011984 return cache->get(i + 1);
11985 }
11986 }
11987
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011988 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011989 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011990
11991 Handle<JSFunctionResultCache> cache_handle(cache);
11992 Handle<Object> key_handle(key);
11993 Handle<Object> value;
11994 {
11995 Handle<JSFunction> factory(JSFunction::cast(
11996 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11997 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011998 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011999 // This handle is nor shared, nor used later, so it's safe.
12000 Object** argv[] = { key_handle.location() };
12001 bool pending_exception = false;
12002 value = Execution::Call(factory,
12003 receiver,
12004 1,
12005 argv,
12006 &pending_exception);
12007 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012008 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012009
12010#ifdef DEBUG
12011 cache_handle->JSFunctionResultCacheVerify();
12012#endif
12013
12014 // Function invocation may have cleared the cache. Reread all the data.
12015 finger_index = cache_handle->finger_index();
12016 size = cache_handle->size();
12017
12018 // If we have spare room, put new data into it, otherwise evict post finger
12019 // entry which is likely to be the least recently used.
12020 int index = -1;
12021 if (size < cache_handle->length()) {
12022 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12023 index = size;
12024 } else {
12025 index = finger_index + JSFunctionResultCache::kEntrySize;
12026 if (index == cache_handle->length()) {
12027 index = JSFunctionResultCache::kEntriesIndex;
12028 }
12029 }
12030
12031 ASSERT(index % 2 == 0);
12032 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12033 ASSERT(index < cache_handle->length());
12034
12035 cache_handle->set(index, *key_handle);
12036 cache_handle->set(index + 1, *value);
12037 cache_handle->set_finger_index(index);
12038
12039#ifdef DEBUG
12040 cache_handle->JSFunctionResultCacheVerify();
12041#endif
12042
12043 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012044}
12045
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012046
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012047static MaybeObject* Runtime_NewMessageObject(RUNTIME_CALLING_CONVENTION) {
12048 RUNTIME_GET_ISOLATE;
12049 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012050 CONVERT_ARG_CHECKED(String, type, 0);
12051 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012052 return *isolate->factory()->NewJSMessageObject(
12053 type,
12054 arguments,
12055 0,
12056 0,
12057 isolate->factory()->undefined_value(),
12058 isolate->factory()->undefined_value(),
12059 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012060}
12061
12062
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012063static MaybeObject* Runtime_MessageGetType(RUNTIME_CALLING_CONVENTION) {
12064 RUNTIME_GET_ISOLATE;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012065 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12066 return message->type();
12067}
12068
12069
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012070static MaybeObject* Runtime_MessageGetArguments(RUNTIME_CALLING_CONVENTION) {
12071 RUNTIME_GET_ISOLATE;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012072 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12073 return message->arguments();
12074}
12075
12076
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012077static MaybeObject* Runtime_MessageGetStartPosition(
12078 RUNTIME_CALLING_CONVENTION) {
12079 RUNTIME_GET_ISOLATE;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012080 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12081 return Smi::FromInt(message->start_position());
12082}
12083
12084
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012085static MaybeObject* Runtime_MessageGetScript(RUNTIME_CALLING_CONVENTION) {
12086 RUNTIME_GET_ISOLATE;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012087 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12088 return message->script();
12089}
12090
12091
kasper.lund44510672008-07-25 07:37:58 +000012092#ifdef DEBUG
12093// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12094// Exclude the code in release mode.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012095static MaybeObject* Runtime_ListNatives(RUNTIME_CALLING_CONVENTION) {
12096 RUNTIME_GET_ISOLATE;
mads.s.ager31e71382008-08-13 09:32:07 +000012097 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012098 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012099#define COUNT_ENTRY(Name, argc, ressize) + 1
12100 int entry_count = 0
12101 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12102 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12103 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12104#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012105 Factory* factory = isolate->factory();
12106 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012107 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012108 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012109#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012110 { \
12111 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012112 Handle<String> name; \
12113 /* Inline runtime functions have an underscore in front of the name. */ \
12114 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012115 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012116 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12117 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012118 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012119 Vector<const char>(#Name, StrLength(#Name))); \
12120 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012121 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012122 pair_elements->set(0, *name); \
12123 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012124 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012125 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012126 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012127 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012128 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012129 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012130 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012131 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012132#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012133 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012134 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012135 return *result;
12136}
kasper.lund44510672008-07-25 07:37:58 +000012137#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012138
12139
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012140static MaybeObject* Runtime_Log(RUNTIME_CALLING_CONVENTION) {
12141 RUNTIME_GET_ISOLATE;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012142 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012143 CONVERT_CHECKED(String, format, args[0]);
12144 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012145 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012146 LOGGER->LogRuntime(chars, elms);
12147 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012148}
12149
12150
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012151static MaybeObject* Runtime_IS_VAR(RUNTIME_CALLING_CONVENTION) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012152 UNREACHABLE(); // implemented as macro in the parser
12153 return NULL;
12154}
12155
12156
12157// ----------------------------------------------------------------------------
12158// Implementation of Runtime
12159
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012160#define F(name, number_of_args, result_size) \
12161 { Runtime::k##name, Runtime::RUNTIME, #name, \
12162 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012163
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012164
12165#define I(name, number_of_args, result_size) \
12166 { Runtime::kInline##name, Runtime::INLINE, \
12167 "_" #name, NULL, number_of_args, result_size },
12168
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012169static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012170 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012171 INLINE_FUNCTION_LIST(I)
12172 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012173};
12174
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012175
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012176MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12177 Object* dictionary) {
12178 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012179 ASSERT(dictionary != NULL);
12180 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12181 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012182 Object* name_symbol;
12183 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012184 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012185 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12186 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012187 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012188 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12189 String::cast(name_symbol),
12190 Smi::FromInt(i),
12191 PropertyDetails(NONE, NORMAL));
12192 if (!maybe_dictionary->ToObject(&dictionary)) {
12193 // Non-recoverable failure. Calling code must restart heap
12194 // initialization.
12195 return maybe_dictionary;
12196 }
12197 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012198 }
12199 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012200}
12201
12202
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012203const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12204 Heap* heap = name->GetHeap();
12205 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012206 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012207 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012208 int function_index = Smi::cast(smi_index)->value();
12209 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012210 }
12211 return NULL;
12212}
12213
12214
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012215const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012216 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12217}
12218
12219
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012220void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012221 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012222 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012223 if (failure->IsRetryAfterGC()) {
12224 // Try to do a garbage collection; ignore it if it fails. The C
12225 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012226 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012227 } else {
12228 // Handle last resort GC and make sure to allow future allocations
12229 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012230 isolate->counters()->gc_last_resort_from_js()->Increment();
12231 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012232 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012233}
12234
12235
12236} } // namespace v8::internal