blob: ceb6c106c9863dd7d58e6bf9331b70256db86c37 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 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
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000227RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000228 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000229 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000230}
231
232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000233RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000234 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000235 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236}
237
238
ager@chromium.org236ad962008-09-25 09:45:57 +0000239static Handle<Map> ComputeObjectLiteralMap(
240 Handle<Context> context,
241 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000242 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000243 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000244 int properties_length = constant_properties->length();
245 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000246 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000247 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000248 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000249 for (int p = 0; p != properties_length; p += 2) {
250 Object* key = constant_properties->get(p);
251 uint32_t element_index = 0;
252 if (key->IsSymbol()) {
253 number_of_symbol_keys++;
254 } else if (key->ToArrayIndex(&element_index)) {
255 // An index key does not require space in the property backing store.
256 number_of_properties--;
257 } else {
258 // Bail out as a non-symbol non-index key makes caching impossible.
259 // ASSERT to make sure that the if condition after the loop is false.
260 ASSERT(number_of_symbol_keys != number_of_properties);
261 break;
262 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000263 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000264 // If we only have symbols and array indices among keys then we can
265 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000266 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000267 if ((number_of_symbol_keys == number_of_properties) &&
268 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000269 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000270 Handle<FixedArray> keys =
271 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000272 if (number_of_symbol_keys > 0) {
273 int index = 0;
274 for (int p = 0; p < properties_length; p += 2) {
275 Object* key = constant_properties->get(p);
276 if (key->IsSymbol()) {
277 keys->set(index++, key);
278 }
279 }
280 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000281 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000282 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000283 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 }
285 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000286 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000287 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000288 Handle<Map>(context->object_function()->initial_map()),
289 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000290}
291
292
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000293static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000294 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000295 Handle<FixedArray> literals,
296 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000297
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000298
299static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000300 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000301 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000302 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000303 bool should_have_fast_elements,
304 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000305 // Get the global context from the literals array. This is the
306 // context in which the function was created and we use the object
307 // function from this context to create the object literal. We do
308 // not use the object function from the current global context
309 // because this might be the object function from another context
310 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000311 Handle<Context> context =
312 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
313
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000314 // In case we have function literals, we want the object to be in
315 // slow properties mode for now. We don't go in the map cache because
316 // maps with constant functions can't be shared if the functions are
317 // not the same (which is the common case).
318 bool is_result_from_cache = false;
319 Handle<Map> map = has_function_literal
320 ? Handle<Map>(context->object_function()->initial_map())
321 : ComputeObjectLiteralMap(context,
322 constant_properties,
323 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000325 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000326
327 // Normalize the elements of the boilerplate to save space if needed.
328 if (!should_have_fast_elements) NormalizeElements(boilerplate);
329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 // Add the constant properties to the boilerplate.
331 int length = constant_properties->length();
332 bool should_transform =
333 !is_result_from_cache && boilerplate->HasFastProperties();
334 if (should_transform || has_function_literal) {
335 // Normalize the properties of object to avoid n^2 behavior
336 // when extending the object multiple properties. Indicate the number of
337 // properties to be added.
338 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
339 }
340
341 for (int index = 0; index < length; index +=2) {
342 Handle<Object> key(constant_properties->get(index+0), isolate);
343 Handle<Object> value(constant_properties->get(index+1), isolate);
344 if (value->IsFixedArray()) {
345 // The value contains the constant_properties of a
346 // simple object or array literal.
347 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
348 value = CreateLiteralBoilerplate(isolate, literals, array);
349 if (value.is_null()) return value;
350 }
351 Handle<Object> result;
352 uint32_t element_index = 0;
353 if (key->IsSymbol()) {
354 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
355 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000356 result = SetOwnElement(boilerplate,
357 element_index,
358 value,
359 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 Handle<String> name(String::cast(*key));
362 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000363 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
364 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000365 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000366 } else if (key->ToArrayIndex(&element_index)) {
367 // Array index (uint32).
368 result = SetOwnElement(boilerplate,
369 element_index,
370 value,
371 kNonStrictMode);
372 } else {
373 // Non-uint32 number.
374 ASSERT(key->IsNumber());
375 double num = key->Number();
376 char arr[100];
377 Vector<char> buffer(arr, ARRAY_SIZE(arr));
378 const char* str = DoubleToCString(num, buffer);
379 Handle<String> name =
380 isolate->factory()->NewStringFromAscii(CStrVector(str));
381 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
382 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000383 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000384 // If setting the property on the boilerplate throws an
385 // exception, the exception is converted to an empty handle in
386 // the handle based operations. In that case, we need to
387 // convert back to an exception.
388 if (result.is_null()) return result;
389 }
390
391 // Transform to fast properties if necessary. For object literals with
392 // containing function literals we defer this operation until after all
393 // computed properties have been assigned so that we can generate
394 // constant function properties.
395 if (should_transform && !has_function_literal) {
396 TransformToFastProperties(boilerplate,
397 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000398 }
399
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000400 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000401}
402
403
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000404static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000406 Handle<FixedArray> literals,
407 Handle<FixedArray> elements) {
408 // Create the JSArray.
409 Handle<JSFunction> constructor(
410 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000411 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000412
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000413 const bool is_cow =
414 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000415 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000416 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000417
418 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000419 if (is_cow) {
420#ifdef DEBUG
421 // Copy-on-write arrays must be shallow (and simple).
422 for (int i = 0; i < content->length(); i++) {
423 ASSERT(!content->get(i)->IsFixedArray());
424 }
425#endif
426 } else {
427 for (int i = 0; i < content->length(); i++) {
428 if (content->get(i)->IsFixedArray()) {
429 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000430 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000431 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
432 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000433 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000434 if (result.is_null()) return result;
435 content->set(i, *result);
436 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000437 }
438 }
439
440 // Set the elements.
441 Handle<JSArray>::cast(object)->SetContent(*content);
442 return object;
443}
444
445
446static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000447 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000448 Handle<FixedArray> literals,
449 Handle<FixedArray> array) {
450 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000451 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000452 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000453 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000454 return CreateObjectLiteralBoilerplate(isolate,
455 literals,
456 elements,
457 true,
458 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000459 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000460 return CreateObjectLiteralBoilerplate(isolate,
461 literals,
462 elements,
463 false,
464 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000465 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000466 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467 default:
468 UNREACHABLE();
469 return Handle<Object>::null();
470 }
471}
472
473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000474RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000475 // Takes a FixedArray of elements containing the literal elements of
476 // the array literal and produces JSArray with those elements.
477 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000478 // which contains the context from which to get the Array function
479 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000480 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000481 ASSERT(args.length() == 3);
482 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
483 CONVERT_SMI_CHECKED(literals_index, args[1]);
484 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000485
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000486 Handle<Object> object =
487 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000488 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000489
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000490 // Update the functions literal and return the boilerplate.
491 literals->set(literals_index, *object);
492 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000493}
494
495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000496RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000497 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000498 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000499 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
500 CONVERT_SMI_CHECKED(literals_index, args[1]);
501 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000502 CONVERT_SMI_CHECKED(flags, args[3]);
503 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
504 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000505
506 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000507 Handle<Object> boilerplate(literals->get(literals_index), isolate);
508 if (*boilerplate == isolate->heap()->undefined_value()) {
509 boilerplate = CreateObjectLiteralBoilerplate(isolate,
510 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000511 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000512 should_have_fast_elements,
513 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000514 if (boilerplate.is_null()) return Failure::Exception();
515 // Update the functions literal and return the boilerplate.
516 literals->set(literals_index, *boilerplate);
517 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000518 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000519}
520
521
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000522RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000523 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000524 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000525 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
526 CONVERT_SMI_CHECKED(literals_index, args[1]);
527 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 CONVERT_SMI_CHECKED(flags, args[3]);
529 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
530 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000531
532 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000533 Handle<Object> boilerplate(literals->get(literals_index), isolate);
534 if (*boilerplate == isolate->heap()->undefined_value()) {
535 boilerplate = CreateObjectLiteralBoilerplate(isolate,
536 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000537 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538 should_have_fast_elements,
539 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000540 if (boilerplate.is_null()) return Failure::Exception();
541 // Update the functions literal and return the boilerplate.
542 literals->set(literals_index, *boilerplate);
543 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000544 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000545}
546
547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000548RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000549 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000550 ASSERT(args.length() == 3);
551 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
552 CONVERT_SMI_CHECKED(literals_index, args[1]);
553 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
554
555 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000556 Handle<Object> boilerplate(literals->get(literals_index), isolate);
557 if (*boilerplate == isolate->heap()->undefined_value()) {
558 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000559 if (boilerplate.is_null()) return Failure::Exception();
560 // Update the functions literal and return the boilerplate.
561 literals->set(literals_index, *boilerplate);
562 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000563 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000564}
565
566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000567RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000569 ASSERT(args.length() == 3);
570 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
571 CONVERT_SMI_CHECKED(literals_index, args[1]);
572 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
573
574 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000575 Handle<Object> boilerplate(literals->get(literals_index), isolate);
576 if (*boilerplate == isolate->heap()->undefined_value()) {
577 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000578 if (boilerplate.is_null()) return Failure::Exception();
579 // Update the functions literal and return the boilerplate.
580 literals->set(literals_index, *boilerplate);
581 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000582 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000584 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000585 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000586 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000587}
588
589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000590RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
ager@chromium.org32912102009-01-16 10:38:43 +0000591 ASSERT(args.length() == 2);
592 CONVERT_CHECKED(String, key, args[0]);
593 Object* value = args[1];
594 // Create a catch context extension object.
595 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000596 isolate->context()->global_context()->
597 context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000598 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000600 if (!maybe_object->ToObject(&object)) return maybe_object;
601 }
ager@chromium.org32912102009-01-16 10:38:43 +0000602 // Assign the exception value to the catch variable and make sure
603 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000604 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000605 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
606 JSObject::cast(object)->SetProperty(
607 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000608 if (!maybe_value->ToObject(&value)) return maybe_value;
609 }
ager@chromium.org32912102009-01-16 10:38:43 +0000610 return object;
611}
612
613
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000614RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615 NoHandleAllocation ha;
616 ASSERT(args.length() == 1);
617 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000619 return JSObject::cast(obj)->class_name();
620}
621
ager@chromium.org7c537e22008-10-16 08:43:32 +0000622
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000623RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624 NoHandleAllocation ha;
625 ASSERT(args.length() == 2);
626 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
627 Object* O = args[0];
628 Object* V = args[1];
629 while (true) {
630 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000631 if (prototype->IsNull()) return isolate->heap()->false_value();
632 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633 V = prototype;
634 }
635}
636
637
ager@chromium.org9085a012009-05-11 19:22:57 +0000638// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000640 NoHandleAllocation ha;
641 ASSERT(args.length() == 2);
642 CONVERT_CHECKED(JSObject, jsobject, args[0]);
643 CONVERT_CHECKED(JSObject, proto, args[1]);
644
645 // Sanity checks. The old prototype (that we are replacing) could
646 // theoretically be null, but if it is not null then check that we
647 // didn't already install a hidden prototype here.
648 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
649 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
650 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
651
652 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000653 Object* map_or_failure;
654 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
655 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
656 return maybe_map_or_failure;
657 }
658 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000659 Map* new_proto_map = Map::cast(map_or_failure);
660
lrn@chromium.org303ada72010-10-27 09:33:13 +0000661 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
662 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
663 return maybe_map_or_failure;
664 }
665 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000666 Map* new_map = Map::cast(map_or_failure);
667
668 // Set proto's prototype to be the old prototype of the object.
669 new_proto_map->set_prototype(jsobject->GetPrototype());
670 proto->set_map(new_proto_map);
671 new_proto_map->set_is_hidden_prototype();
672
673 // Set the object's prototype to proto.
674 new_map->set_prototype(proto);
675 jsobject->set_map(new_map);
676
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000677 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000678}
679
680
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000681RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000682 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000683 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000684 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000685 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000686}
687
688
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000689// Recursively traverses hidden prototypes if property is not found
690static void GetOwnPropertyImplementation(JSObject* obj,
691 String* name,
692 LookupResult* result) {
693 obj->LocalLookupRealNamedProperty(name, result);
694
695 if (!result->IsProperty()) {
696 Object* proto = obj->GetPrototype();
697 if (proto->IsJSObject() &&
698 JSObject::cast(proto)->map()->is_hidden_prototype())
699 GetOwnPropertyImplementation(JSObject::cast(proto),
700 name, result);
701 }
702}
703
704
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000705static bool CheckAccessException(LookupResult* result,
706 v8::AccessType access_type) {
707 if (result->type() == CALLBACKS) {
708 Object* callback = result->GetCallbackObject();
709 if (callback->IsAccessorInfo()) {
710 AccessorInfo* info = AccessorInfo::cast(callback);
711 bool can_access =
712 (access_type == v8::ACCESS_HAS &&
713 (info->all_can_read() || info->all_can_write())) ||
714 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
715 (access_type == v8::ACCESS_SET && info->all_can_write());
716 return can_access;
717 }
718 }
719
720 return false;
721}
722
723
724static bool CheckAccess(JSObject* obj,
725 String* name,
726 LookupResult* result,
727 v8::AccessType access_type) {
728 ASSERT(result->IsProperty());
729
730 JSObject* holder = result->holder();
731 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000732 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000733 while (true) {
734 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000735 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000736 // Access check callback denied the access, but some properties
737 // can have a special permissions which override callbacks descision
738 // (currently see v8::AccessControl).
739 break;
740 }
741
742 if (current == holder) {
743 return true;
744 }
745
746 current = JSObject::cast(current->GetPrototype());
747 }
748
749 // API callbacks can have per callback access exceptions.
750 switch (result->type()) {
751 case CALLBACKS: {
752 if (CheckAccessException(result, access_type)) {
753 return true;
754 }
755 break;
756 }
757 case INTERCEPTOR: {
758 // If the object has an interceptor, try real named properties.
759 // Overwrite the result to fetch the correct property later.
760 holder->LookupRealNamedProperty(name, result);
761 if (result->IsProperty()) {
762 if (CheckAccessException(result, access_type)) {
763 return true;
764 }
765 }
766 break;
767 }
768 default:
769 break;
770 }
771
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000772 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000773 return false;
774}
775
776
777// TODO(1095): we should traverse hidden prototype hierachy as well.
778static bool CheckElementAccess(JSObject* obj,
779 uint32_t index,
780 v8::AccessType access_type) {
781 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000782 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000783 return false;
784 }
785
786 return true;
787}
788
789
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000790// Enumerator used as indices into the array returned from GetOwnProperty
791enum PropertyDescriptorIndices {
792 IS_ACCESSOR_INDEX,
793 VALUE_INDEX,
794 GETTER_INDEX,
795 SETTER_INDEX,
796 WRITABLE_INDEX,
797 ENUMERABLE_INDEX,
798 CONFIGURABLE_INDEX,
799 DESCRIPTOR_SIZE
800};
801
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000802// Returns an array with the property description:
803// if args[1] is not a property on args[0]
804// returns undefined
805// if args[1] is a data property on args[0]
806// [false, value, Writeable, Enumerable, Configurable]
807// if args[1] is an accessor on args[0]
808// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000809RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000810 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000811 Heap* heap = isolate->heap();
812 HandleScope scope(isolate);
813 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
814 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000815 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000816 CONVERT_ARG_CHECKED(JSObject, obj, 0);
817 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000818
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000819 // This could be an element.
820 uint32_t index;
821 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000822 switch (obj->HasLocalElement(index)) {
823 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000824 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000825
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000826 case JSObject::STRING_CHARACTER_ELEMENT: {
827 // Special handling of string objects according to ECMAScript 5
828 // 15.5.5.2. Note that this might be a string object with elements
829 // other than the actual string value. This is covered by the
830 // subsequent cases.
831 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
832 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000833 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000834
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000835 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000836 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000837 elms->set(WRITABLE_INDEX, heap->false_value());
838 elms->set(ENUMERABLE_INDEX, heap->false_value());
839 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000840 return *desc;
841 }
842
843 case JSObject::INTERCEPTED_ELEMENT:
844 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000845 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000846 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000847 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000848 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000849 elms->set(WRITABLE_INDEX, heap->true_value());
850 elms->set(ENUMERABLE_INDEX, heap->true_value());
851 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000852 return *desc;
853 }
854
855 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000856 Handle<JSObject> holder = obj;
857 if (obj->IsJSGlobalProxy()) {
858 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000859 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000860 ASSERT(proto->IsJSGlobalObject());
861 holder = Handle<JSObject>(JSObject::cast(proto));
862 }
863 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000864 int entry = dictionary->FindEntry(index);
865 ASSERT(entry != NumberDictionary::kNotFound);
866 PropertyDetails details = dictionary->DetailsAt(entry);
867 switch (details.type()) {
868 case CALLBACKS: {
869 // This is an accessor property with getter and/or setter.
870 FixedArray* callbacks =
871 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000872 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000873 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
874 elms->set(GETTER_INDEX, callbacks->get(0));
875 }
876 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
877 elms->set(SETTER_INDEX, callbacks->get(1));
878 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000879 break;
880 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000881 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000882 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000883 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000884 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000885 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000886 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000887 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000888 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000889 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000890 default:
891 UNREACHABLE();
892 break;
893 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000894 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
895 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000896 return *desc;
897 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000898 }
899 }
900
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000901 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000902 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000903
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000904 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000905 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000906 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000907
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000908 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000909 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000910 }
911
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000912 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
913 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000914
915 bool is_js_accessor = (result.type() == CALLBACKS) &&
916 (result.GetCallbackObject()->IsFixedArray());
917
918 if (is_js_accessor) {
919 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000920 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000921
922 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
923 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
924 elms->set(GETTER_INDEX, structure->get(0));
925 }
926 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
927 elms->set(SETTER_INDEX, structure->get(1));
928 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000929 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000930 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
931 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000932
933 PropertyAttributes attrs;
934 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000935 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000936 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
937 if (!maybe_value->ToObject(&value)) return maybe_value;
938 }
939 elms->set(VALUE_INDEX, value);
940 }
941
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000942 return *desc;
943}
944
945
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000946RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000947 ASSERT(args.length() == 1);
948 CONVERT_CHECKED(JSObject, obj, args[0]);
949 return obj->PreventExtensions();
950}
951
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000953RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000954 ASSERT(args.length() == 1);
955 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000956 if (obj->IsJSGlobalProxy()) {
957 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000958 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000959 ASSERT(proto->IsJSGlobalObject());
960 obj = JSObject::cast(proto);
961 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000962 return obj->map()->is_extensible() ? isolate->heap()->true_value()
963 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000964}
965
966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000967RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000968 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000969 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000970 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
971 CONVERT_ARG_CHECKED(String, pattern, 1);
972 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000973 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
974 if (result.is_null()) return Failure::Exception();
975 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000976}
977
978
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000979RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000980 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000981 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000982 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000984}
985
986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000987RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 ASSERT(args.length() == 1);
989 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000990 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000991 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992}
993
994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000995RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000996 ASSERT(args.length() == 2);
997 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000999 int index = field->value();
1000 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1001 InstanceType type = templ->map()->instance_type();
1002 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1003 type == OBJECT_TEMPLATE_INFO_TYPE);
1004 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001005 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001006 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1007 } else {
1008 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1009 }
1010 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011}
1012
1013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001014RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001015 ASSERT(args.length() == 1);
1016 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001017 Map* old_map = object->map();
1018 bool needs_access_checks = old_map->is_access_check_needed();
1019 if (needs_access_checks) {
1020 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001021 Object* new_map;
1022 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1023 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1024 }
ager@chromium.org32912102009-01-16 10:38:43 +00001025
1026 Map::cast(new_map)->set_is_access_check_needed(false);
1027 object->set_map(Map::cast(new_map));
1028 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001029 return needs_access_checks ? isolate->heap()->true_value()
1030 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001031}
1032
1033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001034RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001035 ASSERT(args.length() == 1);
1036 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001037 Map* old_map = object->map();
1038 if (!old_map->is_access_check_needed()) {
1039 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001040 Object* new_map;
1041 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1042 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1043 }
ager@chromium.org32912102009-01-16 10:38:43 +00001044
1045 Map::cast(new_map)->set_is_access_check_needed(true);
1046 object->set_map(Map::cast(new_map));
1047 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001048 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001049}
1050
1051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001052static Failure* ThrowRedeclarationError(Isolate* isolate,
1053 const char* type,
1054 Handle<String> name) {
1055 HandleScope scope(isolate);
1056 Handle<Object> type_handle =
1057 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001058 Handle<Object> args[2] = { type_handle, name };
1059 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1061 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001062}
1063
1064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001065RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001066 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001067 HandleScope scope(isolate);
1068 Handle<GlobalObject> global = Handle<GlobalObject>(
1069 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001070
ager@chromium.org3811b432009-10-28 14:53:37 +00001071 Handle<Context> context = args.at<Context>(0);
1072 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001073 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001074 StrictModeFlag strict_mode =
1075 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1076 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001077
1078 // Compute the property attributes. According to ECMA-262, section
1079 // 13, page 71, the property must be read-only and
1080 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1081 // property as read-only, so we don't either.
1082 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1083
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084 // Traverse the name/value pairs and set the properties.
1085 int length = pairs->length();
1086 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001087 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001089 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001090
1091 // We have to declare a global const property. To capture we only
1092 // assign to it when evaluating the assignment for "const x =
1093 // <expr>" the initial value is the hole.
1094 bool is_const_property = value->IsTheHole();
1095
1096 if (value->IsUndefined() || is_const_property) {
1097 // Lookup the property in the global object, and don't set the
1098 // value of the variable if the property is already there.
1099 LookupResult lookup;
1100 global->Lookup(*name, &lookup);
1101 if (lookup.IsProperty()) {
1102 // Determine if the property is local by comparing the holder
1103 // against the global object. The information will be used to
1104 // avoid throwing re-declaration errors when declaring
1105 // variables or constants that exist in the prototype chain.
1106 bool is_local = (*global == lookup.holder());
1107 // Get the property attributes and determine if the property is
1108 // read-only.
1109 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1110 bool is_read_only = (attributes & READ_ONLY) != 0;
1111 if (lookup.type() == INTERCEPTOR) {
1112 // If the interceptor says the property is there, we
1113 // just return undefined without overwriting the property.
1114 // Otherwise, we continue to setting the property.
1115 if (attributes != ABSENT) {
1116 // Check if the existing property conflicts with regards to const.
1117 if (is_local && (is_read_only || is_const_property)) {
1118 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001119 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001120 };
1121 // The property already exists without conflicting: Go to
1122 // the next declaration.
1123 continue;
1124 }
1125 // Fall-through and introduce the absent property by using
1126 // SetProperty.
1127 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001128 // For const properties, we treat a callback with this name
1129 // even in the prototype as a conflicting declaration.
1130 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001131 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001132 }
1133 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001134 if (is_local && (is_read_only || is_const_property)) {
1135 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001136 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001137 }
1138 // The property already exists without conflicting: Go to
1139 // the next declaration.
1140 continue;
1141 }
1142 }
1143 } else {
1144 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001145 Handle<SharedFunctionInfo> shared =
1146 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001147 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001148 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1149 context,
1150 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001151 value = function;
1152 }
1153
1154 LookupResult lookup;
1155 global->LocalLookup(*name, &lookup);
1156
1157 PropertyAttributes attributes = is_const_property
1158 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1159 : base;
1160
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001161 // There's a local property that we need to overwrite because
1162 // we're either declaring a function or there's an interceptor
1163 // that claims the property is absent.
1164 //
1165 // Check for conflicting re-declarations. We cannot have
1166 // conflicting types in case of intercepted properties because
1167 // they are absent.
1168 if (lookup.IsProperty() &&
1169 (lookup.type() != INTERCEPTOR) &&
1170 (lookup.IsReadOnly() || is_const_property)) {
1171 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001172 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001173 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001175 // Safari does not allow the invocation of callback setters for
1176 // function declarations. To mimic this behavior, we do not allow
1177 // the invocation of setters for function values. This makes a
1178 // difference for global functions with the same names as event
1179 // handlers such as "function onload() {}". Firefox does call the
1180 // onload setter in those case and Safari does not. We follow
1181 // Safari for compatibility.
1182 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001183 // Do not change DONT_DELETE to false from true.
1184 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1185 attributes = static_cast<PropertyAttributes>(
1186 attributes | (lookup.GetAttributes() & DONT_DELETE));
1187 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001188 RETURN_IF_EMPTY_HANDLE(isolate,
1189 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001190 name,
1191 value,
1192 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001194 RETURN_IF_EMPTY_HANDLE(isolate,
1195 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001196 name,
1197 value,
1198 attributes,
1199 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001200 }
1201 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001202
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001203 ASSERT(!isolate->has_pending_exception());
1204 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205}
1206
1207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001208RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001209 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001210 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001211
ager@chromium.org7c537e22008-10-16 08:43:32 +00001212 CONVERT_ARG_CHECKED(Context, context, 0);
1213 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001215 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001216 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001217 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218
1219 // Declarations are always done in the function context.
1220 context = Handle<Context>(context->fcontext());
1221
1222 int index;
1223 PropertyAttributes attributes;
1224 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001225 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 context->Lookup(name, flags, &index, &attributes);
1227
1228 if (attributes != ABSENT) {
1229 // The name was declared before; check for conflicting
1230 // re-declarations: This is similar to the code in parser.cc in
1231 // the AstBuildingParser::Declare function.
1232 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1233 // Functions are not read-only.
1234 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1235 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001236 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001237 }
1238
1239 // Initialize it if necessary.
1240 if (*initial_value != NULL) {
1241 if (index >= 0) {
1242 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001243 // the function context or the arguments object.
1244 if (holder->IsContext()) {
1245 ASSERT(holder.is_identical_to(context));
1246 if (((attributes & READ_ONLY) == 0) ||
1247 context->get(index)->IsTheHole()) {
1248 context->set(index, *initial_value);
1249 }
1250 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001251 // The holder is an arguments object.
1252 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001253 Handle<Object> result = SetElement(arguments, index, initial_value,
1254 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001255 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001256 }
1257 } else {
1258 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001259 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001260 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001261 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001262 SetProperty(context_ext, name, initial_value,
1263 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001264 }
1265 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001268 // The property is not in the function context. It needs to be
1269 // "declared" in the function context's extension context, or in the
1270 // global context.
1271 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001272 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001273 // The function context's extension context exists - use it.
1274 context_ext = Handle<JSObject>(context->extension());
1275 } else {
1276 // The function context's extension context does not exists - allocate
1277 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001278 context_ext = isolate->factory()->NewJSObject(
1279 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001280 // And store it in the extension slot.
1281 context->set_extension(*context_ext);
1282 }
1283 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284
ager@chromium.org7c537e22008-10-16 08:43:32 +00001285 // Declare the property by setting it to the initial value if provided,
1286 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1287 // constant declarations).
1288 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001289 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001290 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001291 // Declaring a const context slot is a conflicting declaration if
1292 // there is a callback with that name in a prototype. It is
1293 // allowed to introduce const variables in
1294 // JSContextExtensionObjects. They are treated specially in
1295 // SetProperty and no setters are invoked for those since they are
1296 // not real JSObjects.
1297 if (initial_value->IsTheHole() &&
1298 !context_ext->IsJSContextExtensionObject()) {
1299 LookupResult lookup;
1300 context_ext->Lookup(*name, &lookup);
1301 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001302 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001303 }
1304 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001305 RETURN_IF_EMPTY_HANDLE(isolate,
1306 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001307 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001308 }
1309
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001310 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311}
1312
1313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001314RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001316 // args[0] == name
1317 // args[1] == strict_mode
1318 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319
1320 // Determine if we need to assign to the variable if it already
1321 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001322 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1323 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324
1325 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001326 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001327 RUNTIME_ASSERT(args[1]->IsSmi());
1328 StrictModeFlag strict_mode =
1329 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1330 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331
1332 // According to ECMA-262, section 12.2, page 62, the property must
1333 // not be deletable.
1334 PropertyAttributes attributes = DONT_DELETE;
1335
1336 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001337 // there, there is a property with this name in the prototype chain.
1338 // We follow Safari and Firefox behavior and only set the property
1339 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001340 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001341 // Note that objects can have hidden prototypes, so we need to traverse
1342 // the whole chain of hidden prototypes to do a 'local' lookup.
1343 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001345 while (true) {
1346 real_holder->LocalLookup(*name, &lookup);
1347 if (lookup.IsProperty()) {
1348 // Determine if this is a redeclaration of something read-only.
1349 if (lookup.IsReadOnly()) {
1350 // If we found readonly property on one of hidden prototypes,
1351 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001352 if (real_holder != isolate->context()->global()) break;
1353 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001354 }
1355
1356 // Determine if this is a redeclaration of an intercepted read-only
1357 // property and figure out if the property exists at all.
1358 bool found = true;
1359 PropertyType type = lookup.type();
1360 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001361 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001362 Handle<JSObject> holder(real_holder);
1363 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1364 real_holder = *holder;
1365 if (intercepted == ABSENT) {
1366 // The interceptor claims the property isn't there. We need to
1367 // make sure to introduce it.
1368 found = false;
1369 } else if ((intercepted & READ_ONLY) != 0) {
1370 // The property is present, but read-only. Since we're trying to
1371 // overwrite it with a variable declaration we must throw a
1372 // re-declaration error. However if we found readonly property
1373 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001374 if (real_holder != isolate->context()->global()) break;
1375 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001376 }
1377 }
1378
1379 if (found && !assign) {
1380 // The global property is there and we're not assigning any value
1381 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001382 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001383 }
1384
1385 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001386 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001387 return real_holder->SetProperty(
1388 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001389 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001390
1391 Object* proto = real_holder->GetPrototype();
1392 if (!proto->IsJSObject())
1393 break;
1394
1395 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1396 break;
1397
1398 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 }
1400
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001401 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001402 if (assign) {
1403 return global->SetProperty(*name, args[2], attributes, strict_mode);
1404 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001405 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406}
1407
1408
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001409RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001410 // All constants are declared with an initial value. The name
1411 // of the constant is the first argument and the initial value
1412 // is the second.
1413 RUNTIME_ASSERT(args.length() == 2);
1414 CONVERT_ARG_CHECKED(String, name, 0);
1415 Handle<Object> value = args.at<Object>(1);
1416
1417 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001418 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419
1420 // According to ECMA-262, section 12.2, page 62, the property must
1421 // not be deletable. Since it's a const, it must be READ_ONLY too.
1422 PropertyAttributes attributes =
1423 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1424
1425 // Lookup the property locally in the global object. If it isn't
1426 // there, we add the property and take special precautions to always
1427 // add it as a local property even in case of callbacks in the
1428 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001429 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001430 LookupResult lookup;
1431 global->LocalLookup(*name, &lookup);
1432 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001433 return global->SetLocalPropertyIgnoreAttributes(*name,
1434 *value,
1435 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001436 }
1437
1438 // Determine if this is a redeclaration of something not
1439 // read-only. In case the result is hidden behind an interceptor we
1440 // need to ask it for the property attributes.
1441 if (!lookup.IsReadOnly()) {
1442 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001443 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444 }
1445
1446 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1447
1448 // Throw re-declaration error if the intercepted property is present
1449 // but not read-only.
1450 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001451 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001452 }
1453
1454 // Restore global object from context (in case of GC) and continue
1455 // with setting the value because the property is either absent or
1456 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001457 HandleScope handle_scope(isolate);
1458 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001459
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001460 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001461 // property through an interceptor and only do it if it's
1462 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001463 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001464 RETURN_IF_EMPTY_HANDLE(isolate,
1465 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001466 name,
1467 value,
1468 attributes,
1469 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001470 return *value;
1471 }
1472
1473 // Set the value, but only we're assigning the initial value to a
1474 // constant. For now, we determine this by checking if the
1475 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001476 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001477 PropertyType type = lookup.type();
1478 if (type == FIELD) {
1479 FixedArray* properties = global->properties();
1480 int index = lookup.GetFieldIndex();
1481 if (properties->get(index)->IsTheHole()) {
1482 properties->set(index, *value);
1483 }
1484 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001485 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1486 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001487 }
1488 } else {
1489 // Ignore re-initialization of constants that have already been
1490 // assigned a function value.
1491 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1492 }
1493
1494 // Use the set value as the result of the operation.
1495 return *value;
1496}
1497
1498
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001499RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001500 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501 ASSERT(args.length() == 3);
1502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001503 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001504 ASSERT(!value->IsTheHole());
1505 CONVERT_ARG_CHECKED(Context, context, 1);
1506 Handle<String> name(String::cast(args[2]));
1507
1508 // Initializations are always done in the function context.
1509 context = Handle<Context>(context->fcontext());
1510
1511 int index;
1512 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001513 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001514 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 context->Lookup(name, flags, &index, &attributes);
1516
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001517 // In most situations, the property introduced by the const
1518 // declaration should be present in the context extension object.
1519 // However, because declaration and initialization are separate, the
1520 // property might have been deleted (if it was introduced by eval)
1521 // before we reach the initialization point.
1522 //
1523 // Example:
1524 //
1525 // function f() { eval("delete x; const x;"); }
1526 //
1527 // In that case, the initialization behaves like a normal assignment
1528 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001530 // Property was found in a context.
1531 if (holder->IsContext()) {
1532 // The holder cannot be the function context. If it is, there
1533 // should have been a const redeclaration error when declaring
1534 // the const property.
1535 ASSERT(!holder.is_identical_to(context));
1536 if ((attributes & READ_ONLY) == 0) {
1537 Handle<Context>::cast(holder)->set(index, *value);
1538 }
1539 } else {
1540 // The holder is an arguments object.
1541 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001542 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001543 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001544 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001545 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001546 }
1547 return *value;
1548 }
1549
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001550 // The property could not be found, we introduce it in the global
1551 // context.
1552 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001553 Handle<JSObject> global = Handle<JSObject>(
1554 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001555 // Strict mode not needed (const disallowed in strict mode).
1556 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001557 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001558 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001559 return *value;
1560 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001562 // The property was present in a context extension object.
1563 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001565 if (*context_ext == context->extension()) {
1566 // This is the property that was introduced by the const
1567 // declaration. Set it if it hasn't been set before. NOTE: We
1568 // cannot use GetProperty() to get the current value as it
1569 // 'unholes' the value.
1570 LookupResult lookup;
1571 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1572 ASSERT(lookup.IsProperty()); // the property was declared
1573 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1574
1575 PropertyType type = lookup.type();
1576 if (type == FIELD) {
1577 FixedArray* properties = context_ext->properties();
1578 int index = lookup.GetFieldIndex();
1579 if (properties->get(index)->IsTheHole()) {
1580 properties->set(index, *value);
1581 }
1582 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001583 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1584 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001585 }
1586 } else {
1587 // We should not reach here. Any real, named property should be
1588 // either a field or a dictionary slot.
1589 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001590 }
1591 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001592 // The property was found in a different context extension object.
1593 // Set it if it is not a read-only property.
1594 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001595 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001596 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001597 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001598 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001599 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001600 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001601
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 return *value;
1603}
1604
1605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001606RUNTIME_FUNCTION(MaybeObject*,
1607 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001608 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001609 ASSERT(args.length() == 2);
1610 CONVERT_ARG_CHECKED(JSObject, object, 0);
1611 CONVERT_SMI_CHECKED(properties, args[1]);
1612 if (object->HasFastProperties()) {
1613 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1614 }
1615 return *object;
1616}
1617
1618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001619RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001620 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001621 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001622 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1623 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001624 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001625 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001626 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001627 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001628 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001629 RUNTIME_ASSERT(index >= 0);
1630 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001631 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001632 Handle<Object> result = RegExpImpl::Exec(regexp,
1633 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001634 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001635 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001636 if (result.is_null()) return Failure::Exception();
1637 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001638}
1639
1640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001641RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001642 ASSERT(args.length() == 3);
1643 CONVERT_SMI_CHECKED(elements_count, args[0]);
1644 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001645 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001646 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001647 Object* new_object;
1648 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001649 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001650 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1651 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001652 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001653 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1654 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001655 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1656 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001657 {
1658 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001659 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001660 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001661 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001662 }
1663 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001664 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001665 array->set_elements(elements);
1666 array->set_length(Smi::FromInt(elements_count));
1667 // Write in-object properties after the length of the array.
1668 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1669 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1670 return array;
1671}
1672
1673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001674RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001675 AssertNoAllocation no_alloc;
1676 ASSERT(args.length() == 5);
1677 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1678 CONVERT_CHECKED(String, source, args[1]);
1679
1680 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001681 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001682
1683 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001684 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001685
1686 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001687 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001688
1689 Map* map = regexp->map();
1690 Object* constructor = map->constructor();
1691 if (constructor->IsJSFunction() &&
1692 JSFunction::cast(constructor)->initial_map() == map) {
1693 // If we still have the original map, set in-object properties directly.
1694 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1695 // TODO(lrn): Consider skipping write barrier on booleans as well.
1696 // Both true and false should be in oldspace at all times.
1697 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1698 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1699 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1700 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1701 Smi::FromInt(0),
1702 SKIP_WRITE_BARRIER);
1703 return regexp;
1704 }
1705
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001706 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001707 PropertyAttributes final =
1708 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1709 PropertyAttributes writable =
1710 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001711 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001712 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001713 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001714 source,
1715 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001716 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001717 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001718 global,
1719 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001720 ASSERT(!result->IsFailure());
1721 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001722 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001723 ignoreCase,
1724 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001725 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001726 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001727 multiline,
1728 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001729 ASSERT(!result->IsFailure());
1730 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001732 Smi::FromInt(0),
1733 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001734 ASSERT(!result->IsFailure());
1735 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001736 return regexp;
1737}
1738
1739
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001740RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001741 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001742 ASSERT(args.length() == 1);
1743 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1744 // This is necessary to enable fast checks for absence of elements
1745 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001746 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001747 return Smi::FromInt(0);
1748}
1749
1750
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1752 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001753 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001754 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1756 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1757 Handle<JSFunction> optimized =
1758 isolate->factory()->NewFunction(key,
1759 JS_OBJECT_TYPE,
1760 JSObject::kHeaderSize,
1761 code,
1762 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001763 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001764 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001765 return optimized;
1766}
1767
1768
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001769RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001770 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001771 ASSERT(args.length() == 1);
1772 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1773
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001774 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1775 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1776 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1777 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1778 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1779 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1780 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001781
1782 return *holder;
1783}
1784
1785
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001786RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001787 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001788 Context* global_context =
1789 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001790 return global_context->global()->global_receiver();
1791}
1792
1793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001794RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001795 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001796 ASSERT(args.length() == 4);
1797 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1798 int index = Smi::cast(args[1])->value();
1799 Handle<String> pattern = args.at<String>(2);
1800 Handle<String> flags = args.at<String>(3);
1801
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001802 // Get the RegExp function from the context in the literals array.
1803 // This is the RegExp function from the context in which the
1804 // function was created. We do not use the RegExp function from the
1805 // current global context because this might be the RegExp function
1806 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001807 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001808 Handle<JSFunction>(
1809 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001810 // Compute the regular expression literal.
1811 bool has_pending_exception;
1812 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001813 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1814 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001815 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817 return Failure::Exception();
1818 }
1819 literals->set(index, *regexp);
1820 return *regexp;
1821}
1822
1823
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001824RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001825 NoHandleAllocation ha;
1826 ASSERT(args.length() == 1);
1827
1828 CONVERT_CHECKED(JSFunction, f, args[0]);
1829 return f->shared()->name();
1830}
1831
1832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001833RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001834 NoHandleAllocation ha;
1835 ASSERT(args.length() == 2);
1836
1837 CONVERT_CHECKED(JSFunction, f, args[0]);
1838 CONVERT_CHECKED(String, name, args[1]);
1839 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001840 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001841}
1842
1843
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001844RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001845 NoHandleAllocation ha;
1846 ASSERT(args.length() == 1);
1847
1848 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001849 Object* obj = f->RemovePrototype();
1850 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001851
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001852 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001853}
1854
1855
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001856RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001857 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001858 ASSERT(args.length() == 1);
1859
1860 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001861 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1862 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001863
1864 return *GetScriptWrapper(Handle<Script>::cast(script));
1865}
1866
1867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001868RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
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()->GetSourceCode();
1874}
1875
1876
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001877RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001878 NoHandleAllocation ha;
1879 ASSERT(args.length() == 1);
1880
1881 CONVERT_CHECKED(JSFunction, fun, args[0]);
1882 int pos = fun->shared()->start_position();
1883 return Smi::FromInt(pos);
1884}
1885
1886
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001887RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001888 ASSERT(args.length() == 2);
1889
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001890 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001891 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1892
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001893 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1894
1895 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001896 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001897}
1898
1899
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001900RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001901 NoHandleAllocation ha;
1902 ASSERT(args.length() == 2);
1903
1904 CONVERT_CHECKED(JSFunction, fun, args[0]);
1905 CONVERT_CHECKED(String, name, args[1]);
1906 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001907 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001908}
1909
1910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001911RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001912 NoHandleAllocation ha;
1913 ASSERT(args.length() == 2);
1914
1915 CONVERT_CHECKED(JSFunction, fun, args[0]);
1916 CONVERT_CHECKED(Smi, length, args[1]);
1917 fun->shared()->set_length(length->value());
1918 return length;
1919}
1920
1921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001922RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001923 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001924 ASSERT(args.length() == 2);
1925
1926 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001927 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001928 Object* obj;
1929 { MaybeObject* maybe_obj =
1930 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1931 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1932 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001933 return args[0]; // return TOS
1934}
1935
1936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001937RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001938 NoHandleAllocation ha;
1939 ASSERT(args.length() == 1);
1940
1941 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001942 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1943 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001944}
1945
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001947RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001948 NoHandleAllocation ha;
1949 ASSERT(args.length() == 1);
1950
1951 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001952 return f->IsBuiltin() ? isolate->heap()->true_value() :
1953 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001954}
1955
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001957RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001958 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001959 ASSERT(args.length() == 2);
1960
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001961 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001962 Handle<Object> code = args.at<Object>(1);
1963
1964 Handle<Context> context(target->context());
1965
1966 if (!code->IsNull()) {
1967 RUNTIME_ASSERT(code->IsJSFunction());
1968 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001969 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001970
1971 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001972 return Failure::Exception();
1973 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001974 // Since we don't store the source for this we should never
1975 // optimize this.
1976 shared->code()->set_optimizable(false);
1977
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001978 // Set the code, scope info, formal parameter count,
1979 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001980 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001981 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001982 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001983 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001984 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001985 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001986 // Set the source code of the target function to undefined.
1987 // SetCode is only used for built-in constructors like String,
1988 // Array, and Object, and some web code
1989 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001990 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001991 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001992 // Clear the optimization hints related to the compiled code as these are no
1993 // longer valid when the code is overwritten.
1994 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001995 context = Handle<Context>(fun->context());
1996
1997 // Make sure we get a fresh copy of the literal vector to avoid
1998 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001999 int number_of_literals = fun->NumberOfLiterals();
2000 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002001 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002002 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002003 // Insert the object, regexp and array functions in the literals
2004 // array prefix. These are the functions that will be used when
2005 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002006 literals->set(JSFunction::kLiteralGlobalContextIndex,
2007 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002008 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002009 // It's okay to skip the write barrier here because the literals
2010 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002011 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002012 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 }
2014
2015 target->set_context(*context);
2016 return *target;
2017}
2018
2019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002020RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002021 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002022 ASSERT(args.length() == 2);
2023 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2024 CONVERT_SMI_CHECKED(num, args[1]);
2025 RUNTIME_ASSERT(num >= 0);
2026 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002027 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002028}
2029
2030
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002031MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2032 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002033 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002034 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002035 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002036 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002037 }
2038 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002039 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002040}
2041
2042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002043RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002044 NoHandleAllocation ha;
2045 ASSERT(args.length() == 2);
2046
2047 CONVERT_CHECKED(String, subject, args[0]);
2048 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002049 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002050
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002051 uint32_t i = 0;
2052 if (index->IsSmi()) {
2053 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002054 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002055 i = value;
2056 } else {
2057 ASSERT(index->IsHeapNumber());
2058 double value = HeapNumber::cast(index)->value();
2059 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002060 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002061
2062 // Flatten the string. If someone wants to get a char at an index
2063 // in a cons string, it is likely that more indices will be
2064 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002065 Object* flat;
2066 { MaybeObject* maybe_flat = subject->TryFlatten();
2067 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2068 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002069 subject = String::cast(flat);
2070
2071 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002072 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002073 }
2074
2075 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002076}
2077
2078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002079RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002080 NoHandleAllocation ha;
2081 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002082 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002083}
2084
lrn@chromium.org25156de2010-04-06 13:10:27 +00002085
2086class FixedArrayBuilder {
2087 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002088 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2089 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002090 length_(0) {
2091 // Require a non-zero initial size. Ensures that doubling the size to
2092 // extend the array will work.
2093 ASSERT(initial_capacity > 0);
2094 }
2095
2096 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2097 : array_(backing_store),
2098 length_(0) {
2099 // Require a non-zero initial size. Ensures that doubling the size to
2100 // extend the array will work.
2101 ASSERT(backing_store->length() > 0);
2102 }
2103
2104 bool HasCapacity(int elements) {
2105 int length = array_->length();
2106 int required_length = length_ + elements;
2107 return (length >= required_length);
2108 }
2109
2110 void EnsureCapacity(int elements) {
2111 int length = array_->length();
2112 int required_length = length_ + elements;
2113 if (length < required_length) {
2114 int new_length = length;
2115 do {
2116 new_length *= 2;
2117 } while (new_length < required_length);
2118 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002119 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002120 array_->CopyTo(0, *extended_array, 0, length_);
2121 array_ = extended_array;
2122 }
2123 }
2124
2125 void Add(Object* value) {
2126 ASSERT(length_ < capacity());
2127 array_->set(length_, value);
2128 length_++;
2129 }
2130
2131 void Add(Smi* value) {
2132 ASSERT(length_ < capacity());
2133 array_->set(length_, value);
2134 length_++;
2135 }
2136
2137 Handle<FixedArray> array() {
2138 return array_;
2139 }
2140
2141 int length() {
2142 return length_;
2143 }
2144
2145 int capacity() {
2146 return array_->length();
2147 }
2148
2149 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002150 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002151 result_array->set_length(Smi::FromInt(length_));
2152 return result_array;
2153 }
2154
2155 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2156 target_array->set_elements(*array_);
2157 target_array->set_length(Smi::FromInt(length_));
2158 return target_array;
2159 }
2160
2161 private:
2162 Handle<FixedArray> array_;
2163 int length_;
2164};
2165
2166
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002167// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002168const int kStringBuilderConcatHelperLengthBits = 11;
2169const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002170
2171template <typename schar>
2172static inline void StringBuilderConcatHelper(String*,
2173 schar*,
2174 FixedArray*,
2175 int);
2176
lrn@chromium.org25156de2010-04-06 13:10:27 +00002177typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2178 StringBuilderSubstringLength;
2179typedef BitField<int,
2180 kStringBuilderConcatHelperLengthBits,
2181 kStringBuilderConcatHelperPositionBits>
2182 StringBuilderSubstringPosition;
2183
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002184
2185class ReplacementStringBuilder {
2186 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002187 ReplacementStringBuilder(Heap* heap,
2188 Handle<String> subject,
2189 int estimated_part_count)
2190 : heap_(heap),
2191 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002192 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002193 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002194 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002195 // Require a non-zero initial size. Ensures that doubling the size to
2196 // extend the array will work.
2197 ASSERT(estimated_part_count > 0);
2198 }
2199
lrn@chromium.org25156de2010-04-06 13:10:27 +00002200 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2201 int from,
2202 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002203 ASSERT(from >= 0);
2204 int length = to - from;
2205 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002206 if (StringBuilderSubstringLength::is_valid(length) &&
2207 StringBuilderSubstringPosition::is_valid(from)) {
2208 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2209 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002210 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002211 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002212 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002213 builder->Add(Smi::FromInt(-length));
2214 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002215 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002216 }
2217
2218
2219 void EnsureCapacity(int elements) {
2220 array_builder_.EnsureCapacity(elements);
2221 }
2222
2223
2224 void AddSubjectSlice(int from, int to) {
2225 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002226 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002227 }
2228
2229
2230 void AddString(Handle<String> string) {
2231 int length = string->length();
2232 ASSERT(length > 0);
2233 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002234 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002235 is_ascii_ = false;
2236 }
2237 IncrementCharacterCount(length);
2238 }
2239
2240
2241 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002242 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002243 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002244 }
2245
2246 Handle<String> joined_string;
2247 if (is_ascii_) {
2248 joined_string = NewRawAsciiString(character_count_);
2249 AssertNoAllocation no_alloc;
2250 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2251 char* char_buffer = seq->GetChars();
2252 StringBuilderConcatHelper(*subject_,
2253 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002254 *array_builder_.array(),
2255 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002256 } else {
2257 // Non-ASCII.
2258 joined_string = NewRawTwoByteString(character_count_);
2259 AssertNoAllocation no_alloc;
2260 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2261 uc16* char_buffer = seq->GetChars();
2262 StringBuilderConcatHelper(*subject_,
2263 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002264 *array_builder_.array(),
2265 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002266 }
2267 return joined_string;
2268 }
2269
2270
2271 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002272 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002273 V8::FatalProcessOutOfMemory("String.replace result too large.");
2274 }
2275 character_count_ += by;
2276 }
2277
lrn@chromium.org25156de2010-04-06 13:10:27 +00002278 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002279 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002280 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002281
lrn@chromium.org25156de2010-04-06 13:10:27 +00002282 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002283 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002284 CALL_HEAP_FUNCTION(heap_->isolate(),
2285 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002286 }
2287
2288
2289 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002290 CALL_HEAP_FUNCTION(heap_->isolate(),
2291 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002292 }
2293
2294
2295 void AddElement(Object* element) {
2296 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002297 ASSERT(array_builder_.capacity() > array_builder_.length());
2298 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002299 }
2300
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002301 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002302 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002303 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002304 int character_count_;
2305 bool is_ascii_;
2306};
2307
2308
2309class CompiledReplacement {
2310 public:
2311 CompiledReplacement()
2312 : parts_(1), replacement_substrings_(0) {}
2313
2314 void Compile(Handle<String> replacement,
2315 int capture_count,
2316 int subject_length);
2317
2318 void Apply(ReplacementStringBuilder* builder,
2319 int match_from,
2320 int match_to,
2321 Handle<JSArray> last_match_info);
2322
2323 // Number of distinct parts of the replacement pattern.
2324 int parts() {
2325 return parts_.length();
2326 }
2327 private:
2328 enum PartType {
2329 SUBJECT_PREFIX = 1,
2330 SUBJECT_SUFFIX,
2331 SUBJECT_CAPTURE,
2332 REPLACEMENT_SUBSTRING,
2333 REPLACEMENT_STRING,
2334
2335 NUMBER_OF_PART_TYPES
2336 };
2337
2338 struct ReplacementPart {
2339 static inline ReplacementPart SubjectMatch() {
2340 return ReplacementPart(SUBJECT_CAPTURE, 0);
2341 }
2342 static inline ReplacementPart SubjectCapture(int capture_index) {
2343 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2344 }
2345 static inline ReplacementPart SubjectPrefix() {
2346 return ReplacementPart(SUBJECT_PREFIX, 0);
2347 }
2348 static inline ReplacementPart SubjectSuffix(int subject_length) {
2349 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2350 }
2351 static inline ReplacementPart ReplacementString() {
2352 return ReplacementPart(REPLACEMENT_STRING, 0);
2353 }
2354 static inline ReplacementPart ReplacementSubString(int from, int to) {
2355 ASSERT(from >= 0);
2356 ASSERT(to > from);
2357 return ReplacementPart(-from, to);
2358 }
2359
2360 // If tag <= 0 then it is the negation of a start index of a substring of
2361 // the replacement pattern, otherwise it's a value from PartType.
2362 ReplacementPart(int tag, int data)
2363 : tag(tag), data(data) {
2364 // Must be non-positive or a PartType value.
2365 ASSERT(tag < NUMBER_OF_PART_TYPES);
2366 }
2367 // Either a value of PartType or a non-positive number that is
2368 // the negation of an index into the replacement string.
2369 int tag;
2370 // The data value's interpretation depends on the value of tag:
2371 // tag == SUBJECT_PREFIX ||
2372 // tag == SUBJECT_SUFFIX: data is unused.
2373 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2374 // tag == REPLACEMENT_SUBSTRING ||
2375 // tag == REPLACEMENT_STRING: data is index into array of substrings
2376 // of the replacement string.
2377 // tag <= 0: Temporary representation of the substring of the replacement
2378 // string ranging over -tag .. data.
2379 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2380 // substring objects.
2381 int data;
2382 };
2383
2384 template<typename Char>
2385 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2386 Vector<Char> characters,
2387 int capture_count,
2388 int subject_length) {
2389 int length = characters.length();
2390 int last = 0;
2391 for (int i = 0; i < length; i++) {
2392 Char c = characters[i];
2393 if (c == '$') {
2394 int next_index = i + 1;
2395 if (next_index == length) { // No next character!
2396 break;
2397 }
2398 Char c2 = characters[next_index];
2399 switch (c2) {
2400 case '$':
2401 if (i > last) {
2402 // There is a substring before. Include the first "$".
2403 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2404 last = next_index + 1; // Continue after the second "$".
2405 } else {
2406 // Let the next substring start with the second "$".
2407 last = next_index;
2408 }
2409 i = next_index;
2410 break;
2411 case '`':
2412 if (i > last) {
2413 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2414 }
2415 parts->Add(ReplacementPart::SubjectPrefix());
2416 i = next_index;
2417 last = i + 1;
2418 break;
2419 case '\'':
2420 if (i > last) {
2421 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2422 }
2423 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2424 i = next_index;
2425 last = i + 1;
2426 break;
2427 case '&':
2428 if (i > last) {
2429 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2430 }
2431 parts->Add(ReplacementPart::SubjectMatch());
2432 i = next_index;
2433 last = i + 1;
2434 break;
2435 case '0':
2436 case '1':
2437 case '2':
2438 case '3':
2439 case '4':
2440 case '5':
2441 case '6':
2442 case '7':
2443 case '8':
2444 case '9': {
2445 int capture_ref = c2 - '0';
2446 if (capture_ref > capture_count) {
2447 i = next_index;
2448 continue;
2449 }
2450 int second_digit_index = next_index + 1;
2451 if (second_digit_index < length) {
2452 // Peek ahead to see if we have two digits.
2453 Char c3 = characters[second_digit_index];
2454 if ('0' <= c3 && c3 <= '9') { // Double digits.
2455 int double_digit_ref = capture_ref * 10 + c3 - '0';
2456 if (double_digit_ref <= capture_count) {
2457 next_index = second_digit_index;
2458 capture_ref = double_digit_ref;
2459 }
2460 }
2461 }
2462 if (capture_ref > 0) {
2463 if (i > last) {
2464 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2465 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002466 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002467 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2468 last = next_index + 1;
2469 }
2470 i = next_index;
2471 break;
2472 }
2473 default:
2474 i = next_index;
2475 break;
2476 }
2477 }
2478 }
2479 if (length > last) {
2480 if (last == 0) {
2481 parts->Add(ReplacementPart::ReplacementString());
2482 } else {
2483 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2484 }
2485 }
2486 }
2487
2488 ZoneList<ReplacementPart> parts_;
2489 ZoneList<Handle<String> > replacement_substrings_;
2490};
2491
2492
2493void CompiledReplacement::Compile(Handle<String> replacement,
2494 int capture_count,
2495 int subject_length) {
2496 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002497 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002498 AssertNoAllocation no_alloc;
2499 ParseReplacementPattern(&parts_,
2500 replacement->ToAsciiVector(),
2501 capture_count,
2502 subject_length);
2503 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002504 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002505 AssertNoAllocation no_alloc;
2506
2507 ParseReplacementPattern(&parts_,
2508 replacement->ToUC16Vector(),
2509 capture_count,
2510 subject_length);
2511 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002512 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002513 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002514 int substring_index = 0;
2515 for (int i = 0, n = parts_.length(); i < n; i++) {
2516 int tag = parts_[i].tag;
2517 if (tag <= 0) { // A replacement string slice.
2518 int from = -tag;
2519 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002520 replacement_substrings_.Add(
2521 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002522 parts_[i].tag = REPLACEMENT_SUBSTRING;
2523 parts_[i].data = substring_index;
2524 substring_index++;
2525 } else if (tag == REPLACEMENT_STRING) {
2526 replacement_substrings_.Add(replacement);
2527 parts_[i].data = substring_index;
2528 substring_index++;
2529 }
2530 }
2531}
2532
2533
2534void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2535 int match_from,
2536 int match_to,
2537 Handle<JSArray> last_match_info) {
2538 for (int i = 0, n = parts_.length(); i < n; i++) {
2539 ReplacementPart part = parts_[i];
2540 switch (part.tag) {
2541 case SUBJECT_PREFIX:
2542 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2543 break;
2544 case SUBJECT_SUFFIX: {
2545 int subject_length = part.data;
2546 if (match_to < subject_length) {
2547 builder->AddSubjectSlice(match_to, subject_length);
2548 }
2549 break;
2550 }
2551 case SUBJECT_CAPTURE: {
2552 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002553 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002554 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2555 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2556 if (from >= 0 && to > from) {
2557 builder->AddSubjectSlice(from, to);
2558 }
2559 break;
2560 }
2561 case REPLACEMENT_SUBSTRING:
2562 case REPLACEMENT_STRING:
2563 builder->AddString(replacement_substrings_[part.data]);
2564 break;
2565 default:
2566 UNREACHABLE();
2567 }
2568 }
2569}
2570
2571
2572
lrn@chromium.org303ada72010-10-27 09:33:13 +00002573MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002574 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002575 String* subject,
2576 JSRegExp* regexp,
2577 String* replacement,
2578 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002579 ASSERT(subject->IsFlat());
2580 ASSERT(replacement->IsFlat());
2581
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002582 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002583
2584 int length = subject->length();
2585 Handle<String> subject_handle(subject);
2586 Handle<JSRegExp> regexp_handle(regexp);
2587 Handle<String> replacement_handle(replacement);
2588 Handle<JSArray> last_match_info_handle(last_match_info);
2589 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2590 subject_handle,
2591 0,
2592 last_match_info_handle);
2593 if (match.is_null()) {
2594 return Failure::Exception();
2595 }
2596 if (match->IsNull()) {
2597 return *subject_handle;
2598 }
2599
2600 int capture_count = regexp_handle->CaptureCount();
2601
2602 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002603 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002604 CompiledReplacement compiled_replacement;
2605 compiled_replacement.Compile(replacement_handle,
2606 capture_count,
2607 length);
2608
2609 bool is_global = regexp_handle->GetFlags().is_global();
2610
2611 // Guessing the number of parts that the final result string is built
2612 // from. Global regexps can match any number of times, so we guess
2613 // conservatively.
2614 int expected_parts =
2615 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002616 ReplacementStringBuilder builder(isolate->heap(),
2617 subject_handle,
2618 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002619
2620 // Index of end of last match.
2621 int prev = 0;
2622
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002623 // Number of parts added by compiled replacement plus preceeding
2624 // string and possibly suffix after last match. It is possible for
2625 // all components to use two elements when encoded as two smis.
2626 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002627 bool matched = true;
2628 do {
2629 ASSERT(last_match_info_handle->HasFastElements());
2630 // Increase the capacity of the builder before entering local handle-scope,
2631 // so its internal buffer can safely allocate a new handle if it grows.
2632 builder.EnsureCapacity(parts_added_per_loop);
2633
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002634 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002635 int start, end;
2636 {
2637 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002638 FixedArray* match_info_array =
2639 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002640
2641 ASSERT_EQ(capture_count * 2 + 2,
2642 RegExpImpl::GetLastCaptureCount(match_info_array));
2643 start = RegExpImpl::GetCapture(match_info_array, 0);
2644 end = RegExpImpl::GetCapture(match_info_array, 1);
2645 }
2646
2647 if (prev < start) {
2648 builder.AddSubjectSlice(prev, start);
2649 }
2650 compiled_replacement.Apply(&builder,
2651 start,
2652 end,
2653 last_match_info_handle);
2654 prev = end;
2655
2656 // Only continue checking for global regexps.
2657 if (!is_global) break;
2658
2659 // Continue from where the match ended, unless it was an empty match.
2660 int next = end;
2661 if (start == end) {
2662 next = end + 1;
2663 if (next > length) break;
2664 }
2665
2666 match = RegExpImpl::Exec(regexp_handle,
2667 subject_handle,
2668 next,
2669 last_match_info_handle);
2670 if (match.is_null()) {
2671 return Failure::Exception();
2672 }
2673 matched = !match->IsNull();
2674 } while (matched);
2675
2676 if (prev < length) {
2677 builder.AddSubjectSlice(prev, length);
2678 }
2679
2680 return *(builder.ToString());
2681}
2682
2683
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002684template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002685MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002686 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002687 String* subject,
2688 JSRegExp* regexp,
2689 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002690 ASSERT(subject->IsFlat());
2691
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002692 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002693
2694 Handle<String> subject_handle(subject);
2695 Handle<JSRegExp> regexp_handle(regexp);
2696 Handle<JSArray> last_match_info_handle(last_match_info);
2697 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2698 subject_handle,
2699 0,
2700 last_match_info_handle);
2701 if (match.is_null()) return Failure::Exception();
2702 if (match->IsNull()) return *subject_handle;
2703
2704 ASSERT(last_match_info_handle->HasFastElements());
2705
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002706 int start, end;
2707 {
2708 AssertNoAllocation match_info_array_is_not_in_a_handle;
2709 FixedArray* match_info_array =
2710 FixedArray::cast(last_match_info_handle->elements());
2711
2712 start = RegExpImpl::GetCapture(match_info_array, 0);
2713 end = RegExpImpl::GetCapture(match_info_array, 1);
2714 }
2715
2716 int length = subject->length();
2717 int new_length = length - (end - start);
2718 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002719 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002720 }
2721 Handle<ResultSeqString> answer;
2722 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002723 answer = Handle<ResultSeqString>::cast(
2724 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002725 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002726 answer = Handle<ResultSeqString>::cast(
2727 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002728 }
2729
2730 // If the regexp isn't global, only match once.
2731 if (!regexp_handle->GetFlags().is_global()) {
2732 if (start > 0) {
2733 String::WriteToFlat(*subject_handle,
2734 answer->GetChars(),
2735 0,
2736 start);
2737 }
2738 if (end < length) {
2739 String::WriteToFlat(*subject_handle,
2740 answer->GetChars() + start,
2741 end,
2742 length);
2743 }
2744 return *answer;
2745 }
2746
2747 int prev = 0; // Index of end of last match.
2748 int next = 0; // Start of next search (prev unless last match was empty).
2749 int position = 0;
2750
2751 do {
2752 if (prev < start) {
2753 // Add substring subject[prev;start] to answer string.
2754 String::WriteToFlat(*subject_handle,
2755 answer->GetChars() + position,
2756 prev,
2757 start);
2758 position += start - prev;
2759 }
2760 prev = end;
2761 next = end;
2762 // Continue from where the match ended, unless it was an empty match.
2763 if (start == end) {
2764 next++;
2765 if (next > length) break;
2766 }
2767 match = RegExpImpl::Exec(regexp_handle,
2768 subject_handle,
2769 next,
2770 last_match_info_handle);
2771 if (match.is_null()) return Failure::Exception();
2772 if (match->IsNull()) break;
2773
2774 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002775 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002776 {
2777 AssertNoAllocation match_info_array_is_not_in_a_handle;
2778 FixedArray* match_info_array =
2779 FixedArray::cast(last_match_info_handle->elements());
2780 start = RegExpImpl::GetCapture(match_info_array, 0);
2781 end = RegExpImpl::GetCapture(match_info_array, 1);
2782 }
2783 } while (true);
2784
2785 if (prev < length) {
2786 // Add substring subject[prev;length] to answer string.
2787 String::WriteToFlat(*subject_handle,
2788 answer->GetChars() + position,
2789 prev,
2790 length);
2791 position += length - prev;
2792 }
2793
2794 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002795 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002796 }
2797
2798 // Shorten string and fill
2799 int string_size = ResultSeqString::SizeFor(position);
2800 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2801 int delta = allocated_string_size - string_size;
2802
2803 answer->set_length(position);
2804 if (delta == 0) return *answer;
2805
2806 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002807 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002808
2809 return *answer;
2810}
2811
2812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002813RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002814 ASSERT(args.length() == 4);
2815
2816 CONVERT_CHECKED(String, subject, args[0]);
2817 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002818 Object* flat_subject;
2819 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2820 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2821 return maybe_flat_subject;
2822 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002823 }
2824 subject = String::cast(flat_subject);
2825 }
2826
2827 CONVERT_CHECKED(String, replacement, args[2]);
2828 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002829 Object* flat_replacement;
2830 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2831 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2832 return maybe_flat_replacement;
2833 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002834 }
2835 replacement = String::cast(flat_replacement);
2836 }
2837
2838 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2839 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2840
2841 ASSERT(last_match_info->HasFastElements());
2842
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002843 if (replacement->length() == 0) {
2844 if (subject->HasOnlyAsciiChars()) {
2845 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002846 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002847 } else {
2848 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002849 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002850 }
2851 }
2852
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002853 return StringReplaceRegExpWithString(isolate,
2854 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002855 regexp,
2856 replacement,
2857 last_match_info);
2858}
2859
2860
ager@chromium.org7c537e22008-10-16 08:43:32 +00002861// Perform string match of pattern on subject, starting at start index.
2862// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002863// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002864int Runtime::StringMatch(Isolate* isolate,
2865 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002866 Handle<String> pat,
2867 int start_index) {
2868 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002869 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002870
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002871 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002872 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002873
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002874 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002875 if (start_index + pattern_length > subject_length) return -1;
2876
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002877 if (!sub->IsFlat()) FlattenString(sub);
2878 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002879
ager@chromium.org7c537e22008-10-16 08:43:32 +00002880 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002881 // Extract flattened substrings of cons strings before determining asciiness.
2882 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002883 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002884 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002885 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002886
ager@chromium.org7c537e22008-10-16 08:43:32 +00002887 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002888 if (seq_pat->IsAsciiRepresentation()) {
2889 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2890 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002891 return SearchString(isolate,
2892 seq_sub->ToAsciiVector(),
2893 pat_vector,
2894 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002895 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002896 return SearchString(isolate,
2897 seq_sub->ToUC16Vector(),
2898 pat_vector,
2899 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002900 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002901 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2902 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002903 return SearchString(isolate,
2904 seq_sub->ToAsciiVector(),
2905 pat_vector,
2906 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002907 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002908 return SearchString(isolate,
2909 seq_sub->ToUC16Vector(),
2910 pat_vector,
2911 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002912}
2913
2914
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002915RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002916 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002917 ASSERT(args.length() == 3);
2918
ager@chromium.org7c537e22008-10-16 08:43:32 +00002919 CONVERT_ARG_CHECKED(String, sub, 0);
2920 CONVERT_ARG_CHECKED(String, pat, 1);
2921
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002922 Object* index = args[2];
2923 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002924 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002925
ager@chromium.org870a0b62008-11-04 11:43:05 +00002926 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002927 int position =
2928 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002929 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002930}
2931
2932
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002933template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002934static int StringMatchBackwards(Vector<const schar> subject,
2935 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002936 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002937 int pattern_length = pattern.length();
2938 ASSERT(pattern_length >= 1);
2939 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002940
2941 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002942 for (int i = 0; i < pattern_length; i++) {
2943 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002944 if (c > String::kMaxAsciiCharCode) {
2945 return -1;
2946 }
2947 }
2948 }
2949
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002950 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002951 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002952 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002953 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002954 while (j < pattern_length) {
2955 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002956 break;
2957 }
2958 j++;
2959 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002960 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002961 return i;
2962 }
2963 }
2964 return -1;
2965}
2966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002967RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002968 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002969 ASSERT(args.length() == 3);
2970
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002971 CONVERT_ARG_CHECKED(String, sub, 0);
2972 CONVERT_ARG_CHECKED(String, pat, 1);
2973
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002974 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002975 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002976 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002977
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002978 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002979 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002980
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002981 if (start_index + pat_length > sub_length) {
2982 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002983 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002984
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002985 if (pat_length == 0) {
2986 return Smi::FromInt(start_index);
2987 }
2988
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002989 if (!sub->IsFlat()) FlattenString(sub);
2990 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002991
2992 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2993
2994 int position = -1;
2995
2996 if (pat->IsAsciiRepresentation()) {
2997 Vector<const char> pat_vector = pat->ToAsciiVector();
2998 if (sub->IsAsciiRepresentation()) {
2999 position = StringMatchBackwards(sub->ToAsciiVector(),
3000 pat_vector,
3001 start_index);
3002 } else {
3003 position = StringMatchBackwards(sub->ToUC16Vector(),
3004 pat_vector,
3005 start_index);
3006 }
3007 } else {
3008 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3009 if (sub->IsAsciiRepresentation()) {
3010 position = StringMatchBackwards(sub->ToAsciiVector(),
3011 pat_vector,
3012 start_index);
3013 } else {
3014 position = StringMatchBackwards(sub->ToUC16Vector(),
3015 pat_vector,
3016 start_index);
3017 }
3018 }
3019
3020 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003021}
3022
3023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003024RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003025 NoHandleAllocation ha;
3026 ASSERT(args.length() == 2);
3027
3028 CONVERT_CHECKED(String, str1, args[0]);
3029 CONVERT_CHECKED(String, str2, args[1]);
3030
3031 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003032 int str1_length = str1->length();
3033 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003034
3035 // Decide trivial cases without flattening.
3036 if (str1_length == 0) {
3037 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3038 return Smi::FromInt(-str2_length);
3039 } else {
3040 if (str2_length == 0) return Smi::FromInt(str1_length);
3041 }
3042
3043 int end = str1_length < str2_length ? str1_length : str2_length;
3044
3045 // No need to flatten if we are going to find the answer on the first
3046 // character. At this point we know there is at least one character
3047 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003048 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003049 if (d != 0) return Smi::FromInt(d);
3050
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003051 str1->TryFlatten();
3052 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003053
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003054 StringInputBuffer& buf1 =
3055 *isolate->runtime_state()->string_locale_compare_buf1();
3056 StringInputBuffer& buf2 =
3057 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003058
3059 buf1.Reset(str1);
3060 buf2.Reset(str2);
3061
3062 for (int i = 0; i < end; i++) {
3063 uint16_t char1 = buf1.GetNext();
3064 uint16_t char2 = buf2.GetNext();
3065 if (char1 != char2) return Smi::FromInt(char1 - char2);
3066 }
3067
3068 return Smi::FromInt(str1_length - str2_length);
3069}
3070
3071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003072RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003073 NoHandleAllocation ha;
3074 ASSERT(args.length() == 3);
3075
3076 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003077 Object* from = args[1];
3078 Object* to = args[2];
3079 int start, end;
3080 // We have a fast integer-only case here to avoid a conversion to double in
3081 // the common case where from and to are Smis.
3082 if (from->IsSmi() && to->IsSmi()) {
3083 start = Smi::cast(from)->value();
3084 end = Smi::cast(to)->value();
3085 } else {
3086 CONVERT_DOUBLE_CHECKED(from_number, from);
3087 CONVERT_DOUBLE_CHECKED(to_number, to);
3088 start = FastD2I(from_number);
3089 end = FastD2I(to_number);
3090 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003091 RUNTIME_ASSERT(end >= start);
3092 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003093 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003094 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003095 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003096}
3097
3098
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003099RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003100 ASSERT_EQ(3, args.length());
3101
3102 CONVERT_ARG_CHECKED(String, subject, 0);
3103 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3104 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3105 HandleScope handles;
3106
3107 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3108
3109 if (match.is_null()) {
3110 return Failure::Exception();
3111 }
3112 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003113 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003114 }
3115 int length = subject->length();
3116
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003117 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003118 ZoneList<int> offsets(8);
3119 do {
3120 int start;
3121 int end;
3122 {
3123 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003124 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003125 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3126 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3127 }
3128 offsets.Add(start);
3129 offsets.Add(end);
3130 int index = start < end ? end : end + 1;
3131 if (index > length) break;
3132 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3133 if (match.is_null()) {
3134 return Failure::Exception();
3135 }
3136 } while (!match->IsNull());
3137 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003138 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003139 for (int i = 0; i < matches ; i++) {
3140 int from = offsets.at(i * 2);
3141 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003142 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003143 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003144 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003145 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003146 result->set_length(Smi::FromInt(matches));
3147 return *result;
3148}
3149
3150
lrn@chromium.org25156de2010-04-06 13:10:27 +00003151// Two smis before and after the match, for very long strings.
3152const int kMaxBuilderEntriesPerRegExpMatch = 5;
3153
3154
3155static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3156 Handle<JSArray> last_match_info,
3157 int match_start,
3158 int match_end) {
3159 // Fill last_match_info with a single capture.
3160 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3161 AssertNoAllocation no_gc;
3162 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3163 RegExpImpl::SetLastCaptureCount(elements, 2);
3164 RegExpImpl::SetLastInput(elements, *subject);
3165 RegExpImpl::SetLastSubject(elements, *subject);
3166 RegExpImpl::SetCapture(elements, 0, match_start);
3167 RegExpImpl::SetCapture(elements, 1, match_end);
3168}
3169
3170
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003171template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003172static bool SearchStringMultiple(Isolate* isolate,
3173 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003174 Vector<const PatternChar> pattern,
3175 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003176 FixedArrayBuilder* builder,
3177 int* match_pos) {
3178 int pos = *match_pos;
3179 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003180 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003181 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003182 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003183 while (pos <= max_search_start) {
3184 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3185 *match_pos = pos;
3186 return false;
3187 }
3188 // Position of end of previous match.
3189 int match_end = pos + pattern_length;
3190 int new_pos = search.Search(subject, match_end);
3191 if (new_pos >= 0) {
3192 // A match.
3193 if (new_pos > match_end) {
3194 ReplacementStringBuilder::AddSubjectSlice(builder,
3195 match_end,
3196 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003197 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003198 pos = new_pos;
3199 builder->Add(pattern_string);
3200 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003201 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003202 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003203 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003204
lrn@chromium.org25156de2010-04-06 13:10:27 +00003205 if (pos < max_search_start) {
3206 ReplacementStringBuilder::AddSubjectSlice(builder,
3207 pos + pattern_length,
3208 subject_length);
3209 }
3210 *match_pos = pos;
3211 return true;
3212}
3213
3214
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003215static bool SearchStringMultiple(Isolate* isolate,
3216 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003217 Handle<String> pattern,
3218 Handle<JSArray> last_match_info,
3219 FixedArrayBuilder* builder) {
3220 ASSERT(subject->IsFlat());
3221 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003222
3223 // Treating as if a previous match was before first character.
3224 int match_pos = -pattern->length();
3225
3226 for (;;) { // Break when search complete.
3227 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3228 AssertNoAllocation no_gc;
3229 if (subject->IsAsciiRepresentation()) {
3230 Vector<const char> subject_vector = subject->ToAsciiVector();
3231 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003232 if (SearchStringMultiple(isolate,
3233 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003234 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003235 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003236 builder,
3237 &match_pos)) break;
3238 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003239 if (SearchStringMultiple(isolate,
3240 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003241 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003242 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003243 builder,
3244 &match_pos)) break;
3245 }
3246 } else {
3247 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3248 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003249 if (SearchStringMultiple(isolate,
3250 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003251 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003252 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003253 builder,
3254 &match_pos)) break;
3255 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003256 if (SearchStringMultiple(isolate,
3257 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003258 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003259 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003260 builder,
3261 &match_pos)) break;
3262 }
3263 }
3264 }
3265
3266 if (match_pos >= 0) {
3267 SetLastMatchInfoNoCaptures(subject,
3268 last_match_info,
3269 match_pos,
3270 match_pos + pattern->length());
3271 return true;
3272 }
3273 return false; // No matches at all.
3274}
3275
3276
3277static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003278 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003279 Handle<String> subject,
3280 Handle<JSRegExp> regexp,
3281 Handle<JSArray> last_match_array,
3282 FixedArrayBuilder* builder) {
3283 ASSERT(subject->IsFlat());
3284 int match_start = -1;
3285 int match_end = 0;
3286 int pos = 0;
3287 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3288 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3289
3290 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003291 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003292 int subject_length = subject->length();
3293
3294 for (;;) { // Break on failure, return on exception.
3295 RegExpImpl::IrregexpResult result =
3296 RegExpImpl::IrregexpExecOnce(regexp,
3297 subject,
3298 pos,
3299 register_vector);
3300 if (result == RegExpImpl::RE_SUCCESS) {
3301 match_start = register_vector[0];
3302 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3303 if (match_end < match_start) {
3304 ReplacementStringBuilder::AddSubjectSlice(builder,
3305 match_end,
3306 match_start);
3307 }
3308 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003309 HandleScope loop_scope(isolate);
3310 builder->Add(*isolate->factory()->NewSubString(subject,
3311 match_start,
3312 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003313 if (match_start != match_end) {
3314 pos = match_end;
3315 } else {
3316 pos = match_end + 1;
3317 if (pos > subject_length) break;
3318 }
3319 } else if (result == RegExpImpl::RE_FAILURE) {
3320 break;
3321 } else {
3322 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3323 return result;
3324 }
3325 }
3326
3327 if (match_start >= 0) {
3328 if (match_end < subject_length) {
3329 ReplacementStringBuilder::AddSubjectSlice(builder,
3330 match_end,
3331 subject_length);
3332 }
3333 SetLastMatchInfoNoCaptures(subject,
3334 last_match_array,
3335 match_start,
3336 match_end);
3337 return RegExpImpl::RE_SUCCESS;
3338 } else {
3339 return RegExpImpl::RE_FAILURE; // No matches at all.
3340 }
3341}
3342
3343
3344static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003345 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003346 Handle<String> subject,
3347 Handle<JSRegExp> regexp,
3348 Handle<JSArray> last_match_array,
3349 FixedArrayBuilder* builder) {
3350
3351 ASSERT(subject->IsFlat());
3352 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3353 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3354
3355 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003356 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003357
3358 RegExpImpl::IrregexpResult result =
3359 RegExpImpl::IrregexpExecOnce(regexp,
3360 subject,
3361 0,
3362 register_vector);
3363
3364 int capture_count = regexp->CaptureCount();
3365 int subject_length = subject->length();
3366
3367 // Position to search from.
3368 int pos = 0;
3369 // End of previous match. Differs from pos if match was empty.
3370 int match_end = 0;
3371 if (result == RegExpImpl::RE_SUCCESS) {
3372 // Need to keep a copy of the previous match for creating last_match_info
3373 // at the end, so we have two vectors that we swap between.
3374 OffsetsVector registers2(required_registers);
3375 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3376
3377 do {
3378 int match_start = register_vector[0];
3379 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3380 if (match_end < match_start) {
3381 ReplacementStringBuilder::AddSubjectSlice(builder,
3382 match_end,
3383 match_start);
3384 }
3385 match_end = register_vector[1];
3386
3387 {
3388 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003389 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003390 // Arguments array to replace function is match, captures, index and
3391 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003392 Handle<FixedArray> elements =
3393 isolate->factory()->NewFixedArray(3 + capture_count);
3394 Handle<String> match = isolate->factory()->NewSubString(subject,
3395 match_start,
3396 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003397 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003398 for (int i = 1; i <= capture_count; i++) {
3399 int start = register_vector[i * 2];
3400 if (start >= 0) {
3401 int end = register_vector[i * 2 + 1];
3402 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003403 Handle<String> substring = isolate->factory()->NewSubString(subject,
3404 start,
3405 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003406 elements->set(i, *substring);
3407 } else {
3408 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003409 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003410 }
3411 }
3412 elements->set(capture_count + 1, Smi::FromInt(match_start));
3413 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003414 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003415 }
3416 // Swap register vectors, so the last successful match is in
3417 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003418 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003419 prev_register_vector = register_vector;
3420 register_vector = tmp;
3421
3422 if (match_end > match_start) {
3423 pos = match_end;
3424 } else {
3425 pos = match_end + 1;
3426 if (pos > subject_length) {
3427 break;
3428 }
3429 }
3430
3431 result = RegExpImpl::IrregexpExecOnce(regexp,
3432 subject,
3433 pos,
3434 register_vector);
3435 } while (result == RegExpImpl::RE_SUCCESS);
3436
3437 if (result != RegExpImpl::RE_EXCEPTION) {
3438 // Finished matching, with at least one match.
3439 if (match_end < subject_length) {
3440 ReplacementStringBuilder::AddSubjectSlice(builder,
3441 match_end,
3442 subject_length);
3443 }
3444
3445 int last_match_capture_count = (capture_count + 1) * 2;
3446 int last_match_array_size =
3447 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3448 last_match_array->EnsureSize(last_match_array_size);
3449 AssertNoAllocation no_gc;
3450 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3451 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3452 RegExpImpl::SetLastSubject(elements, *subject);
3453 RegExpImpl::SetLastInput(elements, *subject);
3454 for (int i = 0; i < last_match_capture_count; i++) {
3455 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3456 }
3457 return RegExpImpl::RE_SUCCESS;
3458 }
3459 }
3460 // No matches at all, return failure or exception result directly.
3461 return result;
3462}
3463
3464
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003465RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003466 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003467 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003468
3469 CONVERT_ARG_CHECKED(String, subject, 1);
3470 if (!subject->IsFlat()) { FlattenString(subject); }
3471 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3472 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3473 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3474
3475 ASSERT(last_match_info->HasFastElements());
3476 ASSERT(regexp->GetFlags().is_global());
3477 Handle<FixedArray> result_elements;
3478 if (result_array->HasFastElements()) {
3479 result_elements =
3480 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3481 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003482 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003483 }
3484 FixedArrayBuilder builder(result_elements);
3485
3486 if (regexp->TypeTag() == JSRegExp::ATOM) {
3487 Handle<String> pattern(
3488 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003489 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003490 if (SearchStringMultiple(isolate, subject, pattern,
3491 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003492 return *builder.ToJSArray(result_array);
3493 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003494 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003495 }
3496
3497 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3498
3499 RegExpImpl::IrregexpResult result;
3500 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003501 result = SearchRegExpNoCaptureMultiple(isolate,
3502 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003503 regexp,
3504 last_match_info,
3505 &builder);
3506 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003507 result = SearchRegExpMultiple(isolate,
3508 subject,
3509 regexp,
3510 last_match_info,
3511 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003512 }
3513 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003514 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003515 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3516 return Failure::Exception();
3517}
3518
3519
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003520RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003521 NoHandleAllocation ha;
3522 ASSERT(args.length() == 2);
3523
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003524 // Fast case where the result is a one character string.
3525 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3526 int value = Smi::cast(args[0])->value();
3527 int radix = Smi::cast(args[1])->value();
3528 if (value >= 0 && value < radix) {
3529 RUNTIME_ASSERT(radix <= 36);
3530 // Character array used for conversion.
3531 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003532 return isolate->heap()->
3533 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003534 }
3535 }
3536
3537 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003538 CONVERT_DOUBLE_CHECKED(value, args[0]);
3539 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003540 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003541 }
3542 if (isinf(value)) {
3543 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003544 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003545 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003546 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003547 }
3548 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3549 int radix = FastD2I(radix_number);
3550 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3551 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003552 MaybeObject* result =
3553 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003554 DeleteArray(str);
3555 return result;
3556}
3557
3558
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003559RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003560 NoHandleAllocation ha;
3561 ASSERT(args.length() == 2);
3562
3563 CONVERT_DOUBLE_CHECKED(value, args[0]);
3564 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003565 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003566 }
3567 if (isinf(value)) {
3568 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003569 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003570 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003571 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003572 }
3573 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3574 int f = FastD2I(f_number);
3575 RUNTIME_ASSERT(f >= 0);
3576 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003577 MaybeObject* res =
3578 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003579 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003580 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003581}
3582
3583
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003584RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003585 NoHandleAllocation ha;
3586 ASSERT(args.length() == 2);
3587
3588 CONVERT_DOUBLE_CHECKED(value, args[0]);
3589 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003590 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003591 }
3592 if (isinf(value)) {
3593 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003594 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003595 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003596 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003597 }
3598 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3599 int f = FastD2I(f_number);
3600 RUNTIME_ASSERT(f >= -1 && f <= 20);
3601 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003602 MaybeObject* res =
3603 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003604 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003605 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003606}
3607
3608
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003609RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003610 NoHandleAllocation ha;
3611 ASSERT(args.length() == 2);
3612
3613 CONVERT_DOUBLE_CHECKED(value, args[0]);
3614 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003615 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003616 }
3617 if (isinf(value)) {
3618 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003619 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003621 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622 }
3623 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3624 int f = FastD2I(f_number);
3625 RUNTIME_ASSERT(f >= 1 && f <= 21);
3626 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003627 MaybeObject* res =
3628 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003630 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003631}
3632
3633
3634// Returns a single character string where first character equals
3635// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003636static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003637 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003638 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003639 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003640 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003641 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003642 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643}
3644
3645
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003646MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3647 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003648 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003649 // Handle [] indexing on Strings
3650 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003651 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3652 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003653 }
3654
3655 // Handle [] indexing on String objects
3656 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003657 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3658 Handle<Object> result =
3659 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3660 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003661 }
3662
3663 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003664 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003665 return prototype->GetElement(index);
3666 }
3667
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003668 return GetElement(object, index);
3669}
3670
3671
lrn@chromium.org303ada72010-10-27 09:33:13 +00003672MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003673 return object->GetElement(index);
3674}
3675
3676
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003677MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3678 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003679 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003680 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003681
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003682 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003683 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003684 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003685 isolate->factory()->NewTypeError("non_object_property_load",
3686 HandleVector(args, 2));
3687 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003688 }
3689
3690 // Check if the given key is an array index.
3691 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003692 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003693 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003694 }
3695
3696 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003697 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003698 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003699 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003700 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003701 bool has_pending_exception = false;
3702 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003703 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003704 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003705 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003706 }
3707
ager@chromium.org32912102009-01-16 10:38:43 +00003708 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003709 // the element if so.
3710 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003711 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003712 } else {
3713 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003714 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003715 }
3716}
3717
3718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003719RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003720 NoHandleAllocation ha;
3721 ASSERT(args.length() == 2);
3722
3723 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003724 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003725
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003726 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003727}
3728
3729
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003730// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003731RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003732 NoHandleAllocation ha;
3733 ASSERT(args.length() == 2);
3734
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003735 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003736 // itself.
3737 //
3738 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003739 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003740 // global proxy object never has properties. This is the case
3741 // because the global proxy object forwards everything to its hidden
3742 // prototype including local lookups.
3743 //
3744 // Additionally, we need to make sure that we do not cache results
3745 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003746 if (args[0]->IsJSObject() &&
3747 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003748 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003749 args[1]->IsString()) {
3750 JSObject* receiver = JSObject::cast(args[0]);
3751 String* key = String::cast(args[1]);
3752 if (receiver->HasFastProperties()) {
3753 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003754 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003755 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3756 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003757 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003758 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003759 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003760 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003761 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003762 LookupResult result;
3763 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003764 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003765 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003766 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003767 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003768 }
3769 } else {
3770 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003771 StringDictionary* dictionary = receiver->property_dictionary();
3772 int entry = dictionary->FindEntry(key);
3773 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003774 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003775 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003776 if (!receiver->IsGlobalObject()) return value;
3777 value = JSGlobalPropertyCell::cast(value)->value();
3778 if (!value->IsTheHole()) return value;
3779 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003780 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003781 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003782 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3783 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003784 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003785 Handle<String> str = args.at<String>(0);
3786 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003787 if (index >= 0 && index < str->length()) {
3788 Handle<Object> result = GetCharAt(str, index);
3789 return *result;
3790 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003791 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003792
3793 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003794 return Runtime::GetObjectProperty(isolate,
3795 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003796 args.at<Object>(1));
3797}
3798
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003799// Implements part of 8.12.9 DefineOwnProperty.
3800// There are 3 cases that lead here:
3801// Step 4b - define a new accessor property.
3802// Steps 9c & 12 - replace an existing data property with an accessor property.
3803// Step 12 - update an existing accessor property with an accessor or generic
3804// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003805RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003806 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003807 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003808 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3809 CONVERT_CHECKED(String, name, args[1]);
3810 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003811 Object* fun = args[3];
3812 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003813 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3814 int unchecked = flag_attr->value();
3815 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3816 RUNTIME_ASSERT(!obj->IsNull());
3817 LookupResult result;
3818 obj->LocalLookupRealNamedProperty(name, &result);
3819
3820 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3821 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3822 // delete it to avoid running into trouble in DefineAccessor, which
3823 // handles this incorrectly if the property is readonly (does nothing)
3824 if (result.IsProperty() &&
3825 (result.type() == FIELD || result.type() == NORMAL
3826 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003827 Object* ok;
3828 { MaybeObject* maybe_ok =
3829 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3830 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3831 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003832 }
3833 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3834}
3835
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003836// Implements part of 8.12.9 DefineOwnProperty.
3837// There are 3 cases that lead here:
3838// Step 4a - define a new data property.
3839// Steps 9b & 12 - replace an existing accessor property with a data property.
3840// Step 12 - update an existing data property with a data or generic
3841// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003842RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003843 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003844 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003845 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3846 CONVERT_ARG_CHECKED(String, name, 1);
3847 Handle<Object> obj_value = args.at<Object>(2);
3848
3849 CONVERT_CHECKED(Smi, flag, args[3]);
3850 int unchecked = flag->value();
3851 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3852
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003853 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3854
3855 // Check if this is an element.
3856 uint32_t index;
3857 bool is_element = name->AsArrayIndex(&index);
3858
3859 // Special case for elements if any of the flags are true.
3860 // If elements are in fast case we always implicitly assume that:
3861 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3862 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3863 is_element) {
3864 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003865 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003866 // We do not need to do access checks here since these has already
3867 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003868 Handle<Object> proto(js_object->GetPrototype());
3869 // If proxy is detached, ignore the assignment. Alternatively,
3870 // we could throw an exception.
3871 if (proto->IsNull()) return *obj_value;
3872 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003873 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003874 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003875 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003876 // Make sure that we never go back to fast case.
3877 dictionary->set_requires_slow_elements();
3878 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003879 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003880 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003881 }
3882
ager@chromium.org5c838252010-02-19 08:53:10 +00003883 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003884 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003885
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003886 // To be compatible with safari we do not change the value on API objects
3887 // in defineProperty. Firefox disagrees here, and actually changes the value.
3888 if (result.IsProperty() &&
3889 (result.type() == CALLBACKS) &&
3890 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003891 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003892 }
3893
ager@chromium.org5c838252010-02-19 08:53:10 +00003894 // Take special care when attributes are different and there is already
3895 // a property. For simplicity we normalize the property which enables us
3896 // to not worry about changing the instance_descriptor and creating a new
3897 // map. The current version of SetObjectProperty does not handle attributes
3898 // correctly in the case where a property is a field and is reset with
3899 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003900 if (result.IsProperty() &&
3901 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003902 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003903 if (js_object->IsJSGlobalProxy()) {
3904 // Since the result is a property, the prototype will exist so
3905 // we don't have to check for null.
3906 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003907 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003908 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003909 // Use IgnoreAttributes version since a readonly property may be
3910 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003911 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3912 *obj_value,
3913 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003914 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003915
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003916 return Runtime::ForceSetObjectProperty(isolate,
3917 js_object,
3918 name,
3919 obj_value,
3920 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003921}
3922
3923
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003924MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3925 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003926 Handle<Object> key,
3927 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003928 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003929 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003930 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003931
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003932 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003933 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003934 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003935 isolate->factory()->NewTypeError("non_object_property_store",
3936 HandleVector(args, 2));
3937 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003938 }
3939
3940 // If the object isn't a JavaScript object, we ignore the store.
3941 if (!object->IsJSObject()) return *value;
3942
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003943 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3944
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003945 // Check if the given key is an array index.
3946 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003947 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003948 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3949 // of a string using [] notation. We need to support this too in
3950 // JavaScript.
3951 // In the case of a String object we just need to redirect the assignment to
3952 // the underlying string if the index is in range. Since the underlying
3953 // string does nothing with the assignment then we can ignore such
3954 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003955 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003956 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003957 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003958
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003959 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003960 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003961 return *value;
3962 }
3963
3964 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003965 Handle<Object> result;
3966 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003967 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003968 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003969 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003970 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003971 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003972 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003973 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003974 return *value;
3975 }
3976
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978 bool has_pending_exception = false;
3979 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3980 if (has_pending_exception) return Failure::Exception();
3981 Handle<String> name = Handle<String>::cast(converted);
3982
3983 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003984 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003985 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003986 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003987 }
3988}
3989
3990
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003991MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
3992 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003993 Handle<Object> key,
3994 Handle<Object> value,
3995 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003996 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003997
3998 // Check if the given key is an array index.
3999 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004000 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004001 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4002 // of a string using [] notation. We need to support this too in
4003 // JavaScript.
4004 // In the case of a String object we just need to redirect the assignment to
4005 // the underlying string if the index is in range. Since the underlying
4006 // string does nothing with the assignment then we can ignore such
4007 // assignments.
4008 if (js_object->IsStringObjectWithCharacterAt(index)) {
4009 return *value;
4010 }
4011
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004012 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004013 }
4014
4015 if (key->IsString()) {
4016 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004017 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004018 } else {
4019 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004020 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004021 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4022 *value,
4023 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004024 }
4025 }
4026
4027 // Call-back into JavaScript to convert the key to a string.
4028 bool has_pending_exception = false;
4029 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4030 if (has_pending_exception) return Failure::Exception();
4031 Handle<String> name = Handle<String>::cast(converted);
4032
4033 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004034 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004035 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004036 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004037 }
4038}
4039
4040
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004041MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4042 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004043 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004044 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004045
4046 // Check if the given key is an array index.
4047 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004048 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004049 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4050 // characters of a string using [] notation. In the case of a
4051 // String object we just need to redirect the deletion to the
4052 // underlying string if the index is in range. Since the
4053 // underlying string does nothing with the deletion, we can ignore
4054 // such deletions.
4055 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004056 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004057 }
4058
4059 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4060 }
4061
4062 Handle<String> key_string;
4063 if (key->IsString()) {
4064 key_string = Handle<String>::cast(key);
4065 } else {
4066 // Call-back into JavaScript to convert the key to a string.
4067 bool has_pending_exception = false;
4068 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4069 if (has_pending_exception) return Failure::Exception();
4070 key_string = Handle<String>::cast(converted);
4071 }
4072
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004073 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004074 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4075}
4076
4077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004078RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004079 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004080 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081
4082 Handle<Object> object = args.at<Object>(0);
4083 Handle<Object> key = args.at<Object>(1);
4084 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004085 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4086 RUNTIME_ASSERT(
4087 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004089 PropertyAttributes attributes =
4090 static_cast<PropertyAttributes>(unchecked_attributes);
4091
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004092 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004093 if (args.length() == 5) {
4094 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4095 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4096 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004097 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004099
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004100 return Runtime::SetObjectProperty(isolate,
4101 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004102 key,
4103 value,
4104 attributes,
4105 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004106}
4107
4108
4109// Set a local property, even if it is READ_ONLY. If the property does not
4110// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004111RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004113 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004114 CONVERT_CHECKED(JSObject, object, args[0]);
4115 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004116 // Compute attributes.
4117 PropertyAttributes attributes = NONE;
4118 if (args.length() == 4) {
4119 CONVERT_CHECKED(Smi, value_obj, args[3]);
4120 int unchecked_value = value_obj->value();
4121 // Only attribute bits should be set.
4122 RUNTIME_ASSERT(
4123 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4124 attributes = static_cast<PropertyAttributes>(unchecked_value);
4125 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004127 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004128 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004129}
4130
4131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004132RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004133 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004134 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004135
4136 CONVERT_CHECKED(JSObject, object, args[0]);
4137 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004138 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004139 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004140 ? JSObject::STRICT_DELETION
4141 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004142}
4143
4144
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004145static Object* HasLocalPropertyImplementation(Isolate* isolate,
4146 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004147 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004148 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004149 // Handle hidden prototypes. If there's a hidden prototype above this thing
4150 // then we have to check it for properties, because they are supposed to
4151 // look like they are on this object.
4152 Handle<Object> proto(object->GetPrototype());
4153 if (proto->IsJSObject() &&
4154 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004155 return HasLocalPropertyImplementation(isolate,
4156 Handle<JSObject>::cast(proto),
4157 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004158 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004159 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004160}
4161
4162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004163RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 NoHandleAllocation ha;
4165 ASSERT(args.length() == 2);
4166 CONVERT_CHECKED(String, key, args[1]);
4167
ager@chromium.org9085a012009-05-11 19:22:57 +00004168 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004169 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004170 if (obj->IsJSObject()) {
4171 JSObject* object = JSObject::cast(obj);
4172 // Fast case - no interceptors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004173 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004174 // Slow case. Either it's not there or we have an interceptor. We should
4175 // have handles for this kind of deal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004176 HandleScope scope(isolate);
4177 return HasLocalPropertyImplementation(isolate,
4178 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004179 Handle<String>(key));
4180 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004181 // Well, there is one exception: Handle [] on strings.
4182 uint32_t index;
4183 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00004184 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00004185 if (index < static_cast<uint32_t>(string->length()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004186 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004187 }
4188 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004189 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190}
4191
4192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004193RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194 NoHandleAllocation na;
4195 ASSERT(args.length() == 2);
4196
4197 // Only JS objects can have properties.
4198 if (args[0]->IsJSObject()) {
4199 JSObject* object = JSObject::cast(args[0]);
4200 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004201 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004202 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004203 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004204}
4205
4206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004207RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004208 NoHandleAllocation na;
4209 ASSERT(args.length() == 2);
4210
4211 // Only JS objects can have elements.
4212 if (args[0]->IsJSObject()) {
4213 JSObject* object = JSObject::cast(args[0]);
4214 CONVERT_CHECKED(Smi, index_obj, args[1]);
4215 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004216 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004217 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004218 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004219}
4220
4221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004222RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004223 NoHandleAllocation ha;
4224 ASSERT(args.length() == 2);
4225
4226 CONVERT_CHECKED(JSObject, object, args[0]);
4227 CONVERT_CHECKED(String, key, args[1]);
4228
4229 uint32_t index;
4230 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004231 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004232 }
4233
ager@chromium.org870a0b62008-11-04 11:43:05 +00004234 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004235 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004236}
4237
4238
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004239RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004240 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004241 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004242 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004243 return *GetKeysFor(object);
4244}
4245
4246
4247// Returns either a FixedArray as Runtime_GetPropertyNames,
4248// or, if the given object has an enum cache that contains
4249// all enumerable properties of the object and its prototypes
4250// have none, the map of the object. This is used to speed up
4251// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004252RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004253 ASSERT(args.length() == 1);
4254
4255 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4256
4257 if (raw_object->IsSimpleEnum()) return raw_object->map();
4258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004259 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004260 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004261 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4262 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004263
4264 // Test again, since cache may have been built by preceding call.
4265 if (object->IsSimpleEnum()) return object->map();
4266
4267 return *content;
4268}
4269
4270
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004271// Find the length of the prototype chain that is to to handled as one. If a
4272// prototype object is hidden it is to be viewed as part of the the object it
4273// is prototype for.
4274static int LocalPrototypeChainLength(JSObject* obj) {
4275 int count = 1;
4276 Object* proto = obj->GetPrototype();
4277 while (proto->IsJSObject() &&
4278 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4279 count++;
4280 proto = JSObject::cast(proto)->GetPrototype();
4281 }
4282 return count;
4283}
4284
4285
4286// Return the names of the local named properties.
4287// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004288RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004289 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004290 ASSERT(args.length() == 1);
4291 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004292 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004293 }
4294 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4295
4296 // Skip the global proxy as it has no properties and always delegates to the
4297 // real global object.
4298 if (obj->IsJSGlobalProxy()) {
4299 // Only collect names if access is permitted.
4300 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004301 !isolate->MayNamedAccess(*obj,
4302 isolate->heap()->undefined_value(),
4303 v8::ACCESS_KEYS)) {
4304 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4305 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004306 }
4307 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4308 }
4309
4310 // Find the number of objects making up this.
4311 int length = LocalPrototypeChainLength(*obj);
4312
4313 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004314 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004315 int total_property_count = 0;
4316 Handle<JSObject> jsproto = obj;
4317 for (int i = 0; i < length; i++) {
4318 // Only collect names if access is permitted.
4319 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004320 !isolate->MayNamedAccess(*jsproto,
4321 isolate->heap()->undefined_value(),
4322 v8::ACCESS_KEYS)) {
4323 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4324 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004325 }
4326 int n;
4327 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4328 local_property_count[i] = n;
4329 total_property_count += n;
4330 if (i < length - 1) {
4331 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4332 }
4333 }
4334
4335 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004336 Handle<FixedArray> names =
4337 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004338
4339 // Get the property names.
4340 jsproto = obj;
4341 int proto_with_hidden_properties = 0;
4342 for (int i = 0; i < length; i++) {
4343 jsproto->GetLocalPropertyNames(*names,
4344 i == 0 ? 0 : local_property_count[i - 1]);
4345 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4346 proto_with_hidden_properties++;
4347 }
4348 if (i < length - 1) {
4349 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4350 }
4351 }
4352
4353 // Filter out name of hidden propeties object.
4354 if (proto_with_hidden_properties > 0) {
4355 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004356 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004357 names->length() - proto_with_hidden_properties);
4358 int dest_pos = 0;
4359 for (int i = 0; i < total_property_count; i++) {
4360 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004361 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004362 continue;
4363 }
4364 names->set(dest_pos++, name);
4365 }
4366 }
4367
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004368 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004369}
4370
4371
4372// Return the names of the local indexed properties.
4373// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004374RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004375 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004376 ASSERT(args.length() == 1);
4377 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004378 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004379 }
4380 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4381
4382 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004383 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004384 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004385 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004386}
4387
4388
4389// Return information on whether an object has a named or indexed interceptor.
4390// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004391RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004392 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004393 ASSERT(args.length() == 1);
4394 if (!args[0]->IsJSObject()) {
4395 return Smi::FromInt(0);
4396 }
4397 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4398
4399 int result = 0;
4400 if (obj->HasNamedInterceptor()) result |= 2;
4401 if (obj->HasIndexedInterceptor()) result |= 1;
4402
4403 return Smi::FromInt(result);
4404}
4405
4406
4407// Return property names from named interceptor.
4408// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004409RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004410 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004411 ASSERT(args.length() == 1);
4412 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4413
4414 if (obj->HasNamedInterceptor()) {
4415 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4416 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4417 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004418 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004419}
4420
4421
4422// Return element names from indexed interceptor.
4423// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004424RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004425 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004426 ASSERT(args.length() == 1);
4427 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4428
4429 if (obj->HasIndexedInterceptor()) {
4430 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4431 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4432 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004433 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004434}
4435
4436
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004437RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004438 ASSERT_EQ(args.length(), 1);
4439 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004440 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004441 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004442
4443 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004444 // Do access checks before going to the global object.
4445 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004446 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004447 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004448 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4449 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004450 }
4451
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004452 Handle<Object> proto(object->GetPrototype());
4453 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004454 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004455 object = Handle<JSObject>::cast(proto);
4456 }
4457
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004458 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4459 LOCAL_ONLY);
4460 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4461 // property array and since the result is mutable we have to create
4462 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004463 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004464 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004465 for (int i = 0; i < length; i++) {
4466 Object* entry = contents->get(i);
4467 if (entry->IsString()) {
4468 copy->set(i, entry);
4469 } else {
4470 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004471 HandleScope scope(isolate);
4472 Handle<Object> entry_handle(entry, isolate);
4473 Handle<Object> entry_str =
4474 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004475 copy->set(i, *entry_str);
4476 }
4477 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004478 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004479}
4480
4481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004482RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004483 NoHandleAllocation ha;
4484 ASSERT(args.length() == 1);
4485
4486 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004487 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004488 it.AdvanceToArgumentsFrame();
4489 JavaScriptFrame* frame = it.frame();
4490
4491 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004492 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004493
4494 // Try to convert the key to an index. If successful and within
4495 // index return the the argument from the frame.
4496 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004497 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004498 return frame->GetParameter(index);
4499 }
4500
4501 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004502 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004503 bool exception = false;
4504 Handle<Object> converted =
4505 Execution::ToString(args.at<Object>(0), &exception);
4506 if (exception) return Failure::Exception();
4507 Handle<String> key = Handle<String>::cast(converted);
4508
4509 // Try to convert the string key into an array index.
4510 if (key->AsArrayIndex(&index)) {
4511 if (index < n) {
4512 return frame->GetParameter(index);
4513 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004514 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004515 }
4516 }
4517
4518 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004519 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4520 if (key->Equals(isolate->heap()->callee_symbol())) {
4521 Object* function = frame->function();
4522 if (function->IsJSFunction() &&
4523 JSFunction::cast(function)->shared()->strict_mode()) {
4524 return isolate->Throw(*isolate->factory()->NewTypeError(
4525 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4526 }
4527 return function;
4528 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004529
4530 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004531 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004532}
4533
4534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004535RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004536 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004537
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004538 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004539 Handle<Object> object = args.at<Object>(0);
4540 if (object->IsJSObject()) {
4541 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004542 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004543 MaybeObject* ok = js_object->TransformToFastProperties(0);
4544 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004545 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004546 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004547 return *object;
4548}
4549
4550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004551RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004552 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004553
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004554 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004555 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004556 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004557 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004558 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004559 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004560 return *object;
4561}
4562
4563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004564RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004565 NoHandleAllocation ha;
4566 ASSERT(args.length() == 1);
4567
4568 return args[0]->ToBoolean();
4569}
4570
4571
4572// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4573// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004574RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004575 NoHandleAllocation ha;
4576
4577 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004578 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004579 HeapObject* heap_obj = HeapObject::cast(obj);
4580
4581 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004582 if (heap_obj->map()->is_undetectable()) {
4583 return isolate->heap()->undefined_symbol();
4584 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004585
4586 InstanceType instance_type = heap_obj->map()->instance_type();
4587 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004588 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004589 }
4590
4591 switch (instance_type) {
4592 case ODDBALL_TYPE:
4593 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004594 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004595 }
4596 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004597 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004598 }
4599 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004600 return isolate->heap()->undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004601 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004602 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603 default:
4604 // For any kind of object not handled above, the spec rule for
4605 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004606 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004607 }
4608}
4609
4610
lrn@chromium.org25156de2010-04-06 13:10:27 +00004611static bool AreDigits(const char*s, int from, int to) {
4612 for (int i = from; i < to; i++) {
4613 if (s[i] < '0' || s[i] > '9') return false;
4614 }
4615
4616 return true;
4617}
4618
4619
4620static int ParseDecimalInteger(const char*s, int from, int to) {
4621 ASSERT(to - from < 10); // Overflow is not possible.
4622 ASSERT(from < to);
4623 int d = s[from] - '0';
4624
4625 for (int i = from + 1; i < to; i++) {
4626 d = 10 * d + (s[i] - '0');
4627 }
4628
4629 return d;
4630}
4631
4632
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004633RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004634 NoHandleAllocation ha;
4635 ASSERT(args.length() == 1);
4636 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004637 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004638
4639 // Fast case: short integer or some sorts of junk values.
4640 int len = subject->length();
4641 if (subject->IsSeqAsciiString()) {
4642 if (len == 0) return Smi::FromInt(0);
4643
4644 char const* data = SeqAsciiString::cast(subject)->GetChars();
4645 bool minus = (data[0] == '-');
4646 int start_pos = (minus ? 1 : 0);
4647
4648 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004649 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004650 } else if (data[start_pos] > '9') {
4651 // Fast check for a junk value. A valid string may start from a
4652 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4653 // the 'I' character ('Infinity'). All of that have codes not greater than
4654 // '9' except 'I'.
4655 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004656 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004657 }
4658 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4659 // The maximal/minimal smi has 10 digits. If the string has less digits we
4660 // know it will fit into the smi-data type.
4661 int d = ParseDecimalInteger(data, start_pos, len);
4662 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004663 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004664 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004665 } else if (!subject->HasHashCode() &&
4666 len <= String::kMaxArrayIndexSize &&
4667 (len == 1 || data[0] != '0')) {
4668 // String hash is not calculated yet but all the data are present.
4669 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004670 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004671#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004672 subject->Hash(); // Force hash calculation.
4673 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4674 static_cast<int>(hash));
4675#endif
4676 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004677 }
4678 return Smi::FromInt(d);
4679 }
4680 }
4681
4682 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004683 return isolate->heap()->NumberFromDouble(
4684 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004685}
4686
4687
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004688RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004689 NoHandleAllocation ha;
4690 ASSERT(args.length() == 1);
4691
4692 CONVERT_CHECKED(JSArray, codes, args[0]);
4693 int length = Smi::cast(codes->length())->value();
4694
4695 // Check if the string can be ASCII.
4696 int i;
4697 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004698 Object* element;
4699 { MaybeObject* maybe_element = codes->GetElement(i);
4700 // We probably can't get an exception here, but just in order to enforce
4701 // the checking of inputs in the runtime calls we check here.
4702 if (!maybe_element->ToObject(&element)) return maybe_element;
4703 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004704 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4705 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4706 break;
4707 }
4708
lrn@chromium.org303ada72010-10-27 09:33:13 +00004709 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004710 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004711 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004712 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004713 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004714 }
4715
lrn@chromium.org303ada72010-10-27 09:33:13 +00004716 Object* object = NULL;
4717 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004718 String* result = String::cast(object);
4719 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004720 Object* element;
4721 { MaybeObject* maybe_element = codes->GetElement(i);
4722 if (!maybe_element->ToObject(&element)) return maybe_element;
4723 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004724 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004725 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004726 }
4727 return result;
4728}
4729
4730
4731// kNotEscaped is generated by the following:
4732//
4733// #!/bin/perl
4734// for (my $i = 0; $i < 256; $i++) {
4735// print "\n" if $i % 16 == 0;
4736// my $c = chr($i);
4737// my $escaped = 1;
4738// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4739// print $escaped ? "0, " : "1, ";
4740// }
4741
4742
4743static bool IsNotEscaped(uint16_t character) {
4744 // Only for 8 bit characters, the rest are always escaped (in a different way)
4745 ASSERT(character < 256);
4746 static const char kNotEscaped[256] = {
4747 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4748 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4749 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4750 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4751 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4752 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4753 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4754 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4755 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4756 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4757 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4758 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4759 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4760 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4761 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4762 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4763 };
4764 return kNotEscaped[character] != 0;
4765}
4766
4767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004768RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004769 const char hex_chars[] = "0123456789ABCDEF";
4770 NoHandleAllocation ha;
4771 ASSERT(args.length() == 1);
4772 CONVERT_CHECKED(String, source, args[0]);
4773
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004774 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004775
4776 int escaped_length = 0;
4777 int length = source->length();
4778 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004779 Access<StringInputBuffer> buffer(
4780 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004781 buffer->Reset(source);
4782 while (buffer->has_more()) {
4783 uint16_t character = buffer->GetNext();
4784 if (character >= 256) {
4785 escaped_length += 6;
4786 } else if (IsNotEscaped(character)) {
4787 escaped_length++;
4788 } else {
4789 escaped_length += 3;
4790 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004791 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004792 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004793 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004794 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004795 return Failure::OutOfMemoryException();
4796 }
4797 }
4798 }
4799 // No length change implies no change. Return original string if no change.
4800 if (escaped_length == length) {
4801 return source;
4802 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004803 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004804 { MaybeObject* maybe_o =
4805 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004806 if (!maybe_o->ToObject(&o)) return maybe_o;
4807 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004808 String* destination = String::cast(o);
4809 int dest_position = 0;
4810
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004811 Access<StringInputBuffer> buffer(
4812 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004813 buffer->Rewind();
4814 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004815 uint16_t chr = buffer->GetNext();
4816 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004817 destination->Set(dest_position, '%');
4818 destination->Set(dest_position+1, 'u');
4819 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4820 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4821 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4822 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004823 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004824 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004825 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004826 dest_position++;
4827 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004828 destination->Set(dest_position, '%');
4829 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4830 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831 dest_position += 3;
4832 }
4833 }
4834 return destination;
4835}
4836
4837
4838static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4839 static const signed char kHexValue['g'] = {
4840 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4841 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4842 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4843 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4844 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4845 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4846 -1, 10, 11, 12, 13, 14, 15 };
4847
4848 if (character1 > 'f') return -1;
4849 int hi = kHexValue[character1];
4850 if (hi == -1) return -1;
4851 if (character2 > 'f') return -1;
4852 int lo = kHexValue[character2];
4853 if (lo == -1) return -1;
4854 return (hi << 4) + lo;
4855}
4856
4857
ager@chromium.org870a0b62008-11-04 11:43:05 +00004858static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004859 int i,
4860 int length,
4861 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004862 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004863 int32_t hi = 0;
4864 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004865 if (character == '%' &&
4866 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004867 source->Get(i + 1) == 'u' &&
4868 (hi = TwoDigitHex(source->Get(i + 2),
4869 source->Get(i + 3))) != -1 &&
4870 (lo = TwoDigitHex(source->Get(i + 4),
4871 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004872 *step = 6;
4873 return (hi << 8) + lo;
4874 } else if (character == '%' &&
4875 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004876 (lo = TwoDigitHex(source->Get(i + 1),
4877 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004878 *step = 3;
4879 return lo;
4880 } else {
4881 *step = 1;
4882 return character;
4883 }
4884}
4885
4886
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004887RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004888 NoHandleAllocation ha;
4889 ASSERT(args.length() == 1);
4890 CONVERT_CHECKED(String, source, args[0]);
4891
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004892 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004893
4894 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004895 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004896
4897 int unescaped_length = 0;
4898 for (int i = 0; i < length; unescaped_length++) {
4899 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004900 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004901 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004902 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004903 i += step;
4904 }
4905
4906 // No length change implies no change. Return original string if no change.
4907 if (unescaped_length == length)
4908 return source;
4909
lrn@chromium.org303ada72010-10-27 09:33:13 +00004910 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004911 { MaybeObject* maybe_o =
4912 ascii ?
4913 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
4914 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004915 if (!maybe_o->ToObject(&o)) return maybe_o;
4916 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004917 String* destination = String::cast(o);
4918
4919 int dest_position = 0;
4920 for (int i = 0; i < length; dest_position++) {
4921 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004922 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004923 i += step;
4924 }
4925 return destination;
4926}
4927
4928
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004929static const unsigned int kQuoteTableLength = 128u;
4930
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004931static const int kJsonQuotesCharactersPerEntry = 8;
4932static const char* const JsonQuotes =
4933 "\\u0000 \\u0001 \\u0002 \\u0003 "
4934 "\\u0004 \\u0005 \\u0006 \\u0007 "
4935 "\\b \\t \\n \\u000b "
4936 "\\f \\r \\u000e \\u000f "
4937 "\\u0010 \\u0011 \\u0012 \\u0013 "
4938 "\\u0014 \\u0015 \\u0016 \\u0017 "
4939 "\\u0018 \\u0019 \\u001a \\u001b "
4940 "\\u001c \\u001d \\u001e \\u001f "
4941 " ! \\\" # "
4942 "$ % & ' "
4943 "( ) * + "
4944 ", - . / "
4945 "0 1 2 3 "
4946 "4 5 6 7 "
4947 "8 9 : ; "
4948 "< = > ? "
4949 "@ A B C "
4950 "D E F G "
4951 "H I J K "
4952 "L M N O "
4953 "P Q R S "
4954 "T U V W "
4955 "X Y Z [ "
4956 "\\\\ ] ^ _ "
4957 "` a b c "
4958 "d e f g "
4959 "h i j k "
4960 "l m n o "
4961 "p q r s "
4962 "t u v w "
4963 "x y z { "
4964 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004965
4966
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004967// For a string that is less than 32k characters it should always be
4968// possible to allocate it in new space.
4969static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4970
4971
4972// Doing JSON quoting cannot make the string more than this many times larger.
4973static const int kJsonQuoteWorstCaseBlowup = 6;
4974
4975
4976// Covers the entire ASCII range (all other characters are unchanged by JSON
4977// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004978static const byte JsonQuoteLengths[kQuoteTableLength] = {
4979 6, 6, 6, 6, 6, 6, 6, 6,
4980 2, 2, 2, 6, 2, 2, 6, 6,
4981 6, 6, 6, 6, 6, 6, 6, 6,
4982 6, 6, 6, 6, 6, 6, 6, 6,
4983 1, 1, 2, 1, 1, 1, 1, 1,
4984 1, 1, 1, 1, 1, 1, 1, 1,
4985 1, 1, 1, 1, 1, 1, 1, 1,
4986 1, 1, 1, 1, 1, 1, 1, 1,
4987 1, 1, 1, 1, 1, 1, 1, 1,
4988 1, 1, 1, 1, 1, 1, 1, 1,
4989 1, 1, 1, 1, 1, 1, 1, 1,
4990 1, 1, 1, 1, 2, 1, 1, 1,
4991 1, 1, 1, 1, 1, 1, 1, 1,
4992 1, 1, 1, 1, 1, 1, 1, 1,
4993 1, 1, 1, 1, 1, 1, 1, 1,
4994 1, 1, 1, 1, 1, 1, 1, 1,
4995};
4996
4997
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004998template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004999MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005000
5001
5002template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005003MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5004 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005005}
5006
5007
5008template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005009MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5010 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005011}
5012
5013
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005014template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005015static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5016 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005017 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005018 const Char* read_cursor = characters.start();
5019 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005020 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005021 int quoted_length = kSpaceForQuotes;
5022 while (read_cursor < end) {
5023 Char c = *(read_cursor++);
5024 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5025 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005026 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005027 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005028 }
5029 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005030 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5031 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005032 Object* new_object;
5033 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005034 return new_alloc;
5035 }
5036 StringType* new_string = StringType::cast(new_object);
5037
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005038 Char* write_cursor = reinterpret_cast<Char*>(
5039 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005040 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005041 *(write_cursor++) = '"';
5042
5043 read_cursor = characters.start();
5044 while (read_cursor < end) {
5045 Char c = *(read_cursor++);
5046 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5047 *(write_cursor++) = c;
5048 } else {
5049 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5050 const char* replacement = JsonQuotes +
5051 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5052 for (int i = 0; i < len; i++) {
5053 *write_cursor++ = *replacement++;
5054 }
5055 }
5056 }
5057 *(write_cursor++) = '"';
5058 return new_string;
5059}
5060
5061
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005062template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005063static MaybeObject* QuoteJsonString(Isolate* isolate,
5064 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005065 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005066 isolate->counters()->quote_json_char_count()->Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005067 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005068 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
5069 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005070 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005071 }
5072
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005073 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5074 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005075 Object* new_object;
5076 if (!new_alloc->ToObject(&new_object)) {
5077 return new_alloc;
5078 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005079 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005080 // Even if our string is small enough to fit in new space we still have to
5081 // handle it being allocated in old space as may happen in the third
5082 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5083 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005084 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005085 }
5086 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005087 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005088
5089 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5090 Char* write_cursor = reinterpret_cast<Char*>(
5091 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005092 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005093 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005094
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005095 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005096 const Char* end = read_cursor + length;
5097 while (read_cursor < end) {
5098 Char c = *(read_cursor++);
5099 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5100 *(write_cursor++) = c;
5101 } else {
5102 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5103 const char* replacement = JsonQuotes +
5104 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5105 write_cursor[0] = replacement[0];
5106 if (len > 1) {
5107 write_cursor[1] = replacement[1];
5108 if (len > 2) {
5109 ASSERT(len == 6);
5110 write_cursor[2] = replacement[2];
5111 write_cursor[3] = replacement[3];
5112 write_cursor[4] = replacement[4];
5113 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005114 }
5115 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005116 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005117 }
5118 }
5119 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005120
5121 int final_length = static_cast<int>(
5122 write_cursor - reinterpret_cast<Char*>(
5123 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005124 isolate->heap()->new_space()->
5125 template ShrinkStringAtAllocationBoundary<StringType>(
5126 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005127 return new_string;
5128}
5129
5130
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005131RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005132 NoHandleAllocation ha;
5133 CONVERT_CHECKED(String, str, args[0]);
5134 if (!str->IsFlat()) {
5135 MaybeObject* try_flatten = str->TryFlatten();
5136 Object* flat;
5137 if (!try_flatten->ToObject(&flat)) {
5138 return try_flatten;
5139 }
5140 str = String::cast(flat);
5141 ASSERT(str->IsFlat());
5142 }
5143 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005144 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5145 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005146 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005147 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5148 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005149 }
5150}
5151
5152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005153RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005154 NoHandleAllocation ha;
5155 CONVERT_CHECKED(String, str, args[0]);
5156 if (!str->IsFlat()) {
5157 MaybeObject* try_flatten = str->TryFlatten();
5158 Object* flat;
5159 if (!try_flatten->ToObject(&flat)) {
5160 return try_flatten;
5161 }
5162 str = String::cast(flat);
5163 ASSERT(str->IsFlat());
5164 }
5165 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005166 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5167 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005168 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005169 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5170 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005171 }
5172}
5173
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005174RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005175 NoHandleAllocation ha;
5176
5177 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005178 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005179
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005180 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005181
lrn@chromium.org25156de2010-04-06 13:10:27 +00005182 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005183 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005184 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005185}
5186
5187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005188RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005189 NoHandleAllocation ha;
5190 CONVERT_CHECKED(String, str, args[0]);
5191
5192 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005193 double value = StringToDouble(isolate->unicode_cache(),
5194 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005195
5196 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005197 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005198}
5199
5200
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005201template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005202MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005203 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005204 String* s,
5205 int length,
5206 int input_string_length,
5207 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005208 // We try this twice, once with the assumption that the result is no longer
5209 // than the input and, if that assumption breaks, again with the exact
5210 // length. This may not be pretty, but it is nicer than what was here before
5211 // and I hereby claim my vaffel-is.
5212 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005213 // Allocate the resulting string.
5214 //
5215 // NOTE: This assumes that the upper/lower case of an ascii
5216 // character is also ascii. This is currently the case, but it
5217 // might break in the future if we implement more context and locale
5218 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005219 Object* o;
5220 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005221 ? isolate->heap()->AllocateRawAsciiString(length)
5222 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005223 if (!maybe_o->ToObject(&o)) return maybe_o;
5224 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005225 String* result = String::cast(o);
5226 bool has_changed_character = false;
5227
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005228 // Convert all characters to upper case, assuming that they will fit
5229 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005230 Access<StringInputBuffer> buffer(
5231 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005232 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005233 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005234 // We can assume that the string is not empty
5235 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005236 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005237 bool has_next = buffer->has_more();
5238 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005239 int char_length = mapping->get(current, next, chars);
5240 if (char_length == 0) {
5241 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005242 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005243 i++;
5244 } else if (char_length == 1) {
5245 // Common case: converting the letter resulted in one character.
5246 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005247 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005248 has_changed_character = true;
5249 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005250 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005251 // We've assumed that the result would be as long as the
5252 // input but here is a character that converts to several
5253 // characters. No matter, we calculate the exact length
5254 // of the result and try the whole thing again.
5255 //
5256 // Note that this leaves room for optimization. We could just
5257 // memcpy what we already have to the result string. Also,
5258 // the result string is the last object allocated we could
5259 // "realloc" it and probably, in the vast majority of cases,
5260 // extend the existing string to be able to hold the full
5261 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005262 int next_length = 0;
5263 if (has_next) {
5264 next_length = mapping->get(next, 0, chars);
5265 if (next_length == 0) next_length = 1;
5266 }
5267 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005268 while (buffer->has_more()) {
5269 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005270 // NOTE: we use 0 as the next character here because, while
5271 // the next character may affect what a character converts to,
5272 // it does not in any case affect the length of what it convert
5273 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005274 int char_length = mapping->get(current, 0, chars);
5275 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005276 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005277 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005278 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005279 return Failure::OutOfMemoryException();
5280 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005281 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005282 // Try again with the real length.
5283 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005284 } else {
5285 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005286 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005287 i++;
5288 }
5289 has_changed_character = true;
5290 }
5291 current = next;
5292 }
5293 if (has_changed_character) {
5294 return result;
5295 } else {
5296 // If we didn't actually change anything in doing the conversion
5297 // we simple return the result and let the converted string
5298 // become garbage; there is no reason to keep two identical strings
5299 // alive.
5300 return s;
5301 }
5302}
5303
5304
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005305namespace {
5306
lrn@chromium.org303ada72010-10-27 09:33:13 +00005307static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5308
5309
5310// Given a word and two range boundaries returns a word with high bit
5311// set in every byte iff the corresponding input byte was strictly in
5312// the range (m, n). All the other bits in the result are cleared.
5313// This function is only useful when it can be inlined and the
5314// boundaries are statically known.
5315// Requires: all bytes in the input word and the boundaries must be
5316// ascii (less than 0x7F).
5317static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5318 // Every byte in an ascii string is less than or equal to 0x7F.
5319 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5320 // Use strict inequalities since in edge cases the function could be
5321 // further simplified.
5322 ASSERT(0 < m && m < n && n < 0x7F);
5323 // Has high bit set in every w byte less than n.
5324 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5325 // Has high bit set in every w byte greater than m.
5326 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5327 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5328}
5329
5330
5331enum AsciiCaseConversion {
5332 ASCII_TO_LOWER,
5333 ASCII_TO_UPPER
5334};
5335
5336
5337template <AsciiCaseConversion dir>
5338struct FastAsciiConverter {
5339 static bool Convert(char* dst, char* src, int length) {
5340#ifdef DEBUG
5341 char* saved_dst = dst;
5342 char* saved_src = src;
5343#endif
5344 // We rely on the distance between upper and lower case letters
5345 // being a known power of 2.
5346 ASSERT('a' - 'A' == (1 << 5));
5347 // Boundaries for the range of input characters than require conversion.
5348 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5349 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5350 bool changed = false;
5351 char* const limit = src + length;
5352#ifdef V8_HOST_CAN_READ_UNALIGNED
5353 // Process the prefix of the input that requires no conversion one
5354 // (machine) word at a time.
5355 while (src <= limit - sizeof(uintptr_t)) {
5356 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5357 if (AsciiRangeMask(w, lo, hi) != 0) {
5358 changed = true;
5359 break;
5360 }
5361 *reinterpret_cast<uintptr_t*>(dst) = w;
5362 src += sizeof(uintptr_t);
5363 dst += sizeof(uintptr_t);
5364 }
5365 // Process the remainder of the input performing conversion when
5366 // required one word at a time.
5367 while (src <= limit - sizeof(uintptr_t)) {
5368 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5369 uintptr_t m = AsciiRangeMask(w, lo, hi);
5370 // The mask has high (7th) bit set in every byte that needs
5371 // conversion and we know that the distance between cases is
5372 // 1 << 5.
5373 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5374 src += sizeof(uintptr_t);
5375 dst += sizeof(uintptr_t);
5376 }
5377#endif
5378 // Process the last few bytes of the input (or the whole input if
5379 // unaligned access is not supported).
5380 while (src < limit) {
5381 char c = *src;
5382 if (lo < c && c < hi) {
5383 c ^= (1 << 5);
5384 changed = true;
5385 }
5386 *dst = c;
5387 ++src;
5388 ++dst;
5389 }
5390#ifdef DEBUG
5391 CheckConvert(saved_dst, saved_src, length, changed);
5392#endif
5393 return changed;
5394 }
5395
5396#ifdef DEBUG
5397 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5398 bool expected_changed = false;
5399 for (int i = 0; i < length; i++) {
5400 if (dst[i] == src[i]) continue;
5401 expected_changed = true;
5402 if (dir == ASCII_TO_LOWER) {
5403 ASSERT('A' <= src[i] && src[i] <= 'Z');
5404 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5405 } else {
5406 ASSERT(dir == ASCII_TO_UPPER);
5407 ASSERT('a' <= src[i] && src[i] <= 'z');
5408 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5409 }
5410 }
5411 ASSERT(expected_changed == changed);
5412 }
5413#endif
5414};
5415
5416
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005417struct ToLowerTraits {
5418 typedef unibrow::ToLowercase UnibrowConverter;
5419
lrn@chromium.org303ada72010-10-27 09:33:13 +00005420 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005421};
5422
5423
5424struct ToUpperTraits {
5425 typedef unibrow::ToUppercase UnibrowConverter;
5426
lrn@chromium.org303ada72010-10-27 09:33:13 +00005427 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005428};
5429
5430} // namespace
5431
5432
5433template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005434MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005435 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005436 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005437 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005438 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005439 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005440 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005441
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005442 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005443 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005444 if (length == 0) return s;
5445
5446 // Simpler handling of ascii strings.
5447 //
5448 // NOTE: This assumes that the upper/lower case of an ascii
5449 // character is also ascii. This is currently the case, but it
5450 // might break in the future if we implement more context and locale
5451 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005452 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005453 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005454 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005455 if (!maybe_o->ToObject(&o)) return maybe_o;
5456 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005457 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005458 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005459 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005460 return has_changed_character ? result : s;
5461 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005462
lrn@chromium.org303ada72010-10-27 09:33:13 +00005463 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005464 { MaybeObject* maybe_answer =
5465 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005466 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5467 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005468 if (answer->IsSmi()) {
5469 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005470 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005471 ConvertCaseHelper(isolate,
5472 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005473 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5474 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005475 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005476 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005477}
5478
5479
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005480RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005481 return ConvertCase<ToLowerTraits>(
5482 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005483}
5484
5485
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005486RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005487 return ConvertCase<ToUpperTraits>(
5488 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005489}
5490
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005491
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005492static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5493 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5494}
5495
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005497RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005498 NoHandleAllocation ha;
5499 ASSERT(args.length() == 3);
5500
5501 CONVERT_CHECKED(String, s, args[0]);
5502 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5503 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5504
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005505 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005506 int length = s->length();
5507
5508 int left = 0;
5509 if (trimLeft) {
5510 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5511 left++;
5512 }
5513 }
5514
5515 int right = length;
5516 if (trimRight) {
5517 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5518 right--;
5519 }
5520 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005521 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005522}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005523
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005524
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005525template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005526void FindStringIndices(Isolate* isolate,
5527 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005528 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005529 ZoneList<int>* indices,
5530 unsigned int limit) {
5531 ASSERT(limit > 0);
5532 // Collect indices of pattern in subject, and the end-of-string index.
5533 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005534 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005535 int pattern_length = pattern.length();
5536 int index = 0;
5537 while (limit > 0) {
5538 index = search.Search(subject, index);
5539 if (index < 0) return;
5540 indices->Add(index);
5541 index += pattern_length;
5542 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005543 }
5544}
5545
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005547RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005548 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005549 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005550 CONVERT_ARG_CHECKED(String, subject, 0);
5551 CONVERT_ARG_CHECKED(String, pattern, 1);
5552 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5553
5554 int subject_length = subject->length();
5555 int pattern_length = pattern->length();
5556 RUNTIME_ASSERT(pattern_length > 0);
5557
5558 // The limit can be very large (0xffffffffu), but since the pattern
5559 // isn't empty, we can never create more parts than ~half the length
5560 // of the subject.
5561
5562 if (!subject->IsFlat()) FlattenString(subject);
5563
5564 static const int kMaxInitialListCapacity = 16;
5565
5566 ZoneScope scope(DELETE_ON_EXIT);
5567
5568 // Find (up to limit) indices of separator and end-of-string in subject
5569 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5570 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005571 if (!pattern->IsFlat()) FlattenString(pattern);
5572
5573 // No allocation block.
5574 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005575 AssertNoAllocation nogc;
5576 if (subject->IsAsciiRepresentation()) {
5577 Vector<const char> subject_vector = subject->ToAsciiVector();
5578 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005579 FindStringIndices(isolate,
5580 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005581 pattern->ToAsciiVector(),
5582 &indices,
5583 limit);
5584 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005585 FindStringIndices(isolate,
5586 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005587 pattern->ToUC16Vector(),
5588 &indices,
5589 limit);
5590 }
5591 } else {
5592 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5593 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005594 FindStringIndices(isolate,
5595 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005596 pattern->ToAsciiVector(),
5597 &indices,
5598 limit);
5599 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005600 FindStringIndices(isolate,
5601 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005602 pattern->ToUC16Vector(),
5603 &indices,
5604 limit);
5605 }
5606 }
5607 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005608
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005609 if (static_cast<uint32_t>(indices.length()) < limit) {
5610 indices.Add(subject_length);
5611 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005612
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005613 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005614
5615 // Create JSArray of substrings separated by separator.
5616 int part_count = indices.length();
5617
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005618 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005619 result->set_length(Smi::FromInt(part_count));
5620
5621 ASSERT(result->HasFastElements());
5622
5623 if (part_count == 1 && indices.at(0) == subject_length) {
5624 FixedArray::cast(result->elements())->set(0, *subject);
5625 return *result;
5626 }
5627
5628 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5629 int part_start = 0;
5630 for (int i = 0; i < part_count; i++) {
5631 HandleScope local_loop_handle;
5632 int part_end = indices.at(i);
5633 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005634 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005635 elements->set(i, *substring);
5636 part_start = part_end + pattern_length;
5637 }
5638
5639 return *result;
5640}
5641
5642
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005643// Copies ascii characters to the given fixed array looking up
5644// one-char strings in the cache. Gives up on the first char that is
5645// not in the cache and fills the remainder with smi zeros. Returns
5646// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005647static int CopyCachedAsciiCharsToArray(Heap* heap,
5648 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005649 FixedArray* elements,
5650 int length) {
5651 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005652 FixedArray* ascii_cache = heap->single_character_string_cache();
5653 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005654 int i;
5655 for (i = 0; i < length; ++i) {
5656 Object* value = ascii_cache->get(chars[i]);
5657 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005658 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005659 elements->set(i, value, SKIP_WRITE_BARRIER);
5660 }
5661 if (i < length) {
5662 ASSERT(Smi::FromInt(0) == 0);
5663 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5664 }
5665#ifdef DEBUG
5666 for (int j = 0; j < length; ++j) {
5667 Object* element = elements->get(j);
5668 ASSERT(element == Smi::FromInt(0) ||
5669 (element->IsString() && String::cast(element)->LooksValid()));
5670 }
5671#endif
5672 return i;
5673}
5674
5675
5676// Converts a String to JSArray.
5677// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005678RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005679 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005680 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005681 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005682 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005683
5684 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005685 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005686
5687 Handle<FixedArray> elements;
5688 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005689 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005690 { MaybeObject* maybe_obj =
5691 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005692 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5693 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005694 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005695
5696 Vector<const char> chars = s->ToAsciiVector();
5697 // Note, this will initialize all elements (not only the prefix)
5698 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005699 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5700 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005701 *elements,
5702 length);
5703
5704 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005705 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5706 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005707 }
5708 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005709 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005710 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005711 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5712 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005713 }
5714 }
5715
5716#ifdef DEBUG
5717 for (int i = 0; i < length; ++i) {
5718 ASSERT(String::cast(elements->get(i))->length() == 1);
5719 }
5720#endif
5721
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005722 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005723}
5724
5725
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005726RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005727 NoHandleAllocation ha;
5728 ASSERT(args.length() == 1);
5729 CONVERT_CHECKED(String, value, args[0]);
5730 return value->ToObject();
5731}
5732
5733
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005734bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005735 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005736 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005737 return char_length == 0;
5738}
5739
5740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005741RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005742 NoHandleAllocation ha;
5743 ASSERT(args.length() == 1);
5744
5745 Object* number = args[0];
5746 RUNTIME_ASSERT(number->IsNumber());
5747
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005748 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005749}
5750
5751
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005752RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005753 NoHandleAllocation ha;
5754 ASSERT(args.length() == 1);
5755
5756 Object* number = args[0];
5757 RUNTIME_ASSERT(number->IsNumber());
5758
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005759 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005760}
5761
5762
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005763RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005764 NoHandleAllocation ha;
5765 ASSERT(args.length() == 1);
5766
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005767 CONVERT_DOUBLE_CHECKED(number, args[0]);
5768
5769 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5770 if (number > 0 && number <= Smi::kMaxValue) {
5771 return Smi::FromInt(static_cast<int>(number));
5772 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005773 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005774}
5775
5776
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005777RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005778 NoHandleAllocation ha;
5779 ASSERT(args.length() == 1);
5780
5781 CONVERT_DOUBLE_CHECKED(number, args[0]);
5782
5783 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5784 if (number > 0 && number <= Smi::kMaxValue) {
5785 return Smi::FromInt(static_cast<int>(number));
5786 }
5787
5788 double double_value = DoubleToInteger(number);
5789 // Map both -0 and +0 to +0.
5790 if (double_value == 0) double_value = 0;
5791
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005792 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005793}
5794
5795
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005796RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005797 NoHandleAllocation ha;
5798 ASSERT(args.length() == 1);
5799
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005800 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005801 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005802}
5803
5804
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005805RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005806 NoHandleAllocation ha;
5807 ASSERT(args.length() == 1);
5808
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005809 CONVERT_DOUBLE_CHECKED(number, args[0]);
5810
5811 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5812 if (number > 0 && number <= Smi::kMaxValue) {
5813 return Smi::FromInt(static_cast<int>(number));
5814 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005815 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005816}
5817
5818
ager@chromium.org870a0b62008-11-04 11:43:05 +00005819// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5820// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005821RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005822 NoHandleAllocation ha;
5823 ASSERT(args.length() == 1);
5824
5825 Object* obj = args[0];
5826 if (obj->IsSmi()) {
5827 return obj;
5828 }
5829 if (obj->IsHeapNumber()) {
5830 double value = HeapNumber::cast(obj)->value();
5831 int int_value = FastD2I(value);
5832 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5833 return Smi::FromInt(int_value);
5834 }
5835 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005836 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005837}
5838
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005840RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005841 NoHandleAllocation ha;
5842 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005843 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005844}
5845
5846
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005847RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005848 NoHandleAllocation ha;
5849 ASSERT(args.length() == 2);
5850
5851 CONVERT_DOUBLE_CHECKED(x, args[0]);
5852 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005853 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005854}
5855
5856
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005857RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005858 NoHandleAllocation ha;
5859 ASSERT(args.length() == 2);
5860
5861 CONVERT_DOUBLE_CHECKED(x, args[0]);
5862 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005863 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005864}
5865
5866
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005867RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005868 NoHandleAllocation ha;
5869 ASSERT(args.length() == 2);
5870
5871 CONVERT_DOUBLE_CHECKED(x, args[0]);
5872 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005873 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005874}
5875
5876
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005877RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005878 NoHandleAllocation ha;
5879 ASSERT(args.length() == 1);
5880
5881 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005882 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005883}
5884
5885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005886RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005887 NoHandleAllocation ha;
5888 ASSERT(args.length() == 0);
5889
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005890 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005891}
5892
5893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005894RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005895 NoHandleAllocation ha;
5896 ASSERT(args.length() == 2);
5897
5898 CONVERT_DOUBLE_CHECKED(x, args[0]);
5899 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005900 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005901}
5902
5903
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005904RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005905 NoHandleAllocation ha;
5906 ASSERT(args.length() == 2);
5907
5908 CONVERT_DOUBLE_CHECKED(x, args[0]);
5909 CONVERT_DOUBLE_CHECKED(y, args[1]);
5910
ager@chromium.org3811b432009-10-28 14:53:37 +00005911 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005912 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005913 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005914}
5915
5916
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005917RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918 NoHandleAllocation ha;
5919 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005920 CONVERT_CHECKED(String, str1, args[0]);
5921 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005922 isolate->counters()->string_add_runtime()->Increment();
5923 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005924}
5925
5926
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005927template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005928static inline void StringBuilderConcatHelper(String* special,
5929 sinkchar* sink,
5930 FixedArray* fixed_array,
5931 int array_length) {
5932 int position = 0;
5933 for (int i = 0; i < array_length; i++) {
5934 Object* element = fixed_array->get(i);
5935 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005936 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005937 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005938 int pos;
5939 int len;
5940 if (encoded_slice > 0) {
5941 // Position and length encoded in one smi.
5942 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5943 len = StringBuilderSubstringLength::decode(encoded_slice);
5944 } else {
5945 // Position and length encoded in two smis.
5946 Object* obj = fixed_array->get(++i);
5947 ASSERT(obj->IsSmi());
5948 pos = Smi::cast(obj)->value();
5949 len = -encoded_slice;
5950 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005951 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005952 sink + position,
5953 pos,
5954 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005955 position += len;
5956 } else {
5957 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005958 int element_length = string->length();
5959 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005960 position += element_length;
5961 }
5962 }
5963}
5964
5965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005966RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005967 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005968 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005969 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005970 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005971 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005972 return Failure::OutOfMemoryException();
5973 }
5974 int array_length = Smi::cast(args[1])->value();
5975 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005976
5977 // This assumption is used by the slice encoding in one or two smis.
5978 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5979
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005980 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005981 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005982 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005983 }
5984 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005985 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005986 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005987 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005988
5989 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005990 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005991 } else if (array_length == 1) {
5992 Object* first = fixed_array->get(0);
5993 if (first->IsString()) return first;
5994 }
5995
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005996 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005997 int position = 0;
5998 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005999 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006000 Object* elt = fixed_array->get(i);
6001 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006002 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006003 int smi_value = Smi::cast(elt)->value();
6004 int pos;
6005 int len;
6006 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006007 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006008 pos = StringBuilderSubstringPosition::decode(smi_value);
6009 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006010 } else {
6011 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006012 len = -smi_value;
6013 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006014 i++;
6015 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006016 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006017 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006018 Object* next_smi = fixed_array->get(i);
6019 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006020 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006021 }
6022 pos = Smi::cast(next_smi)->value();
6023 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006024 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006025 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006026 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006027 ASSERT(pos >= 0);
6028 ASSERT(len >= 0);
6029 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006030 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006031 }
6032 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006033 } else if (elt->IsString()) {
6034 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006035 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006036 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006037 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006038 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006039 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006041 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006042 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006043 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006044 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006045 return Failure::OutOfMemoryException();
6046 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006047 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006048 }
6049
6050 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006051 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006052
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006053 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006054 { MaybeObject* maybe_object =
6055 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006056 if (!maybe_object->ToObject(&object)) return maybe_object;
6057 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006058 SeqAsciiString* answer = SeqAsciiString::cast(object);
6059 StringBuilderConcatHelper(special,
6060 answer->GetChars(),
6061 fixed_array,
6062 array_length);
6063 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006064 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006065 { MaybeObject* maybe_object =
6066 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006067 if (!maybe_object->ToObject(&object)) return maybe_object;
6068 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006069 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6070 StringBuilderConcatHelper(special,
6071 answer->GetChars(),
6072 fixed_array,
6073 array_length);
6074 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006075 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006076}
6077
6078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006079RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006080 NoHandleAllocation ha;
6081 ASSERT(args.length() == 3);
6082 CONVERT_CHECKED(JSArray, array, args[0]);
6083 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006084 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006085 return Failure::OutOfMemoryException();
6086 }
6087 int array_length = Smi::cast(args[1])->value();
6088 CONVERT_CHECKED(String, separator, args[2]);
6089
6090 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006091 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006092 }
6093 FixedArray* fixed_array = FixedArray::cast(array->elements());
6094 if (fixed_array->length() < array_length) {
6095 array_length = fixed_array->length();
6096 }
6097
6098 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006099 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006100 } else if (array_length == 1) {
6101 Object* first = fixed_array->get(0);
6102 if (first->IsString()) return first;
6103 }
6104
6105 int separator_length = separator->length();
6106 int max_nof_separators =
6107 (String::kMaxLength + separator_length - 1) / separator_length;
6108 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006109 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006110 return Failure::OutOfMemoryException();
6111 }
6112 int length = (array_length - 1) * separator_length;
6113 for (int i = 0; i < array_length; i++) {
6114 Object* element_obj = fixed_array->get(i);
6115 if (!element_obj->IsString()) {
6116 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006117 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006118 }
6119 String* element = String::cast(element_obj);
6120 int increment = element->length();
6121 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006122 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006123 return Failure::OutOfMemoryException();
6124 }
6125 length += increment;
6126 }
6127
6128 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006129 { MaybeObject* maybe_object =
6130 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006131 if (!maybe_object->ToObject(&object)) return maybe_object;
6132 }
6133 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6134
6135 uc16* sink = answer->GetChars();
6136#ifdef DEBUG
6137 uc16* end = sink + length;
6138#endif
6139
6140 String* first = String::cast(fixed_array->get(0));
6141 int first_length = first->length();
6142 String::WriteToFlat(first, sink, 0, first_length);
6143 sink += first_length;
6144
6145 for (int i = 1; i < array_length; i++) {
6146 ASSERT(sink + separator_length <= end);
6147 String::WriteToFlat(separator, sink, 0, separator_length);
6148 sink += separator_length;
6149
6150 String* element = String::cast(fixed_array->get(i));
6151 int element_length = element->length();
6152 ASSERT(sink + element_length <= end);
6153 String::WriteToFlat(element, sink, 0, element_length);
6154 sink += element_length;
6155 }
6156 ASSERT(sink == end);
6157
6158 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6159 return answer;
6160}
6161
6162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006163RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006164 NoHandleAllocation ha;
6165 ASSERT(args.length() == 2);
6166
6167 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6168 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006169 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006170}
6171
6172
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006173RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006174 NoHandleAllocation ha;
6175 ASSERT(args.length() == 2);
6176
6177 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6178 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006179 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006180}
6181
6182
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006183RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006184 NoHandleAllocation ha;
6185 ASSERT(args.length() == 2);
6186
6187 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6188 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006189 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006190}
6191
6192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006193RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006194 NoHandleAllocation ha;
6195 ASSERT(args.length() == 1);
6196
6197 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006198 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006199}
6200
6201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006202RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006203 NoHandleAllocation ha;
6204 ASSERT(args.length() == 2);
6205
6206 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6207 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006208 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006209}
6210
6211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006212RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006213 NoHandleAllocation ha;
6214 ASSERT(args.length() == 2);
6215
6216 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6217 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006218 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006219}
6220
6221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006222RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006223 NoHandleAllocation ha;
6224 ASSERT(args.length() == 2);
6225
6226 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6227 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006228 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006229}
6230
6231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006232RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006233 NoHandleAllocation ha;
6234 ASSERT(args.length() == 2);
6235
6236 CONVERT_DOUBLE_CHECKED(x, args[0]);
6237 CONVERT_DOUBLE_CHECKED(y, args[1]);
6238 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6239 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6240 if (x == y) return Smi::FromInt(EQUAL);
6241 Object* result;
6242 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6243 result = Smi::FromInt(EQUAL);
6244 } else {
6245 result = Smi::FromInt(NOT_EQUAL);
6246 }
6247 return result;
6248}
6249
6250
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006251RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006252 NoHandleAllocation ha;
6253 ASSERT(args.length() == 2);
6254
6255 CONVERT_CHECKED(String, x, args[0]);
6256 CONVERT_CHECKED(String, y, args[1]);
6257
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006258 bool not_equal = !x->Equals(y);
6259 // This is slightly convoluted because the value that signifies
6260 // equality is 0 and inequality is 1 so we have to negate the result
6261 // from String::Equals.
6262 ASSERT(not_equal == 0 || not_equal == 1);
6263 STATIC_CHECK(EQUAL == 0);
6264 STATIC_CHECK(NOT_EQUAL == 1);
6265 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006266}
6267
6268
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006269RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006270 NoHandleAllocation ha;
6271 ASSERT(args.length() == 3);
6272
6273 CONVERT_DOUBLE_CHECKED(x, args[0]);
6274 CONVERT_DOUBLE_CHECKED(y, args[1]);
6275 if (isnan(x) || isnan(y)) return args[2];
6276 if (x == y) return Smi::FromInt(EQUAL);
6277 if (isless(x, y)) return Smi::FromInt(LESS);
6278 return Smi::FromInt(GREATER);
6279}
6280
6281
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006282// Compare two Smis as if they were converted to strings and then
6283// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006284RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006285 NoHandleAllocation ha;
6286 ASSERT(args.length() == 2);
6287
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006288 // Extract the integer values from the Smis.
6289 CONVERT_CHECKED(Smi, x, args[0]);
6290 CONVERT_CHECKED(Smi, y, args[1]);
6291 int x_value = x->value();
6292 int y_value = y->value();
6293
6294 // If the integers are equal so are the string representations.
6295 if (x_value == y_value) return Smi::FromInt(EQUAL);
6296
6297 // If one of the integers are zero the normal integer order is the
6298 // same as the lexicographic order of the string representations.
6299 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6300
ager@chromium.org32912102009-01-16 10:38:43 +00006301 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006302 // smallest because the char code of '-' is less than the char code
6303 // of any digit. Otherwise, we make both values positive.
6304 if (x_value < 0 || y_value < 0) {
6305 if (y_value >= 0) return Smi::FromInt(LESS);
6306 if (x_value >= 0) return Smi::FromInt(GREATER);
6307 x_value = -x_value;
6308 y_value = -y_value;
6309 }
6310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006311 // Arrays for the individual characters of the two Smis. Smis are
6312 // 31 bit integers and 10 decimal digits are therefore enough.
6313 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6314 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6315 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6316
6317
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006318 // Convert the integers to arrays of their decimal digits.
6319 int x_index = 0;
6320 int y_index = 0;
6321 while (x_value > 0) {
6322 x_elms[x_index++] = x_value % 10;
6323 x_value /= 10;
6324 }
6325 while (y_value > 0) {
6326 y_elms[y_index++] = y_value % 10;
6327 y_value /= 10;
6328 }
6329
6330 // Loop through the arrays of decimal digits finding the first place
6331 // where they differ.
6332 while (--x_index >= 0 && --y_index >= 0) {
6333 int diff = x_elms[x_index] - y_elms[y_index];
6334 if (diff != 0) return Smi::FromInt(diff);
6335 }
6336
6337 // If one array is a suffix of the other array, the longest array is
6338 // the representation of the largest of the Smis in the
6339 // lexicographic ordering.
6340 return Smi::FromInt(x_index - y_index);
6341}
6342
6343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006344static Object* StringInputBufferCompare(RuntimeState* state,
6345 String* x,
6346 String* y) {
6347 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6348 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006349 bufx.Reset(x);
6350 bufy.Reset(y);
6351 while (bufx.has_more() && bufy.has_more()) {
6352 int d = bufx.GetNext() - bufy.GetNext();
6353 if (d < 0) return Smi::FromInt(LESS);
6354 else if (d > 0) return Smi::FromInt(GREATER);
6355 }
6356
6357 // x is (non-trivial) prefix of y:
6358 if (bufy.has_more()) return Smi::FromInt(LESS);
6359 // y is prefix of x:
6360 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6361}
6362
6363
6364static Object* FlatStringCompare(String* x, String* y) {
6365 ASSERT(x->IsFlat());
6366 ASSERT(y->IsFlat());
6367 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6368 int prefix_length = x->length();
6369 if (y->length() < prefix_length) {
6370 prefix_length = y->length();
6371 equal_prefix_result = Smi::FromInt(GREATER);
6372 } else if (y->length() > prefix_length) {
6373 equal_prefix_result = Smi::FromInt(LESS);
6374 }
6375 int r;
6376 if (x->IsAsciiRepresentation()) {
6377 Vector<const char> x_chars = x->ToAsciiVector();
6378 if (y->IsAsciiRepresentation()) {
6379 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006380 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006381 } else {
6382 Vector<const uc16> y_chars = y->ToUC16Vector();
6383 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6384 }
6385 } else {
6386 Vector<const uc16> x_chars = x->ToUC16Vector();
6387 if (y->IsAsciiRepresentation()) {
6388 Vector<const char> y_chars = y->ToAsciiVector();
6389 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6390 } else {
6391 Vector<const uc16> y_chars = y->ToUC16Vector();
6392 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6393 }
6394 }
6395 Object* result;
6396 if (r == 0) {
6397 result = equal_prefix_result;
6398 } else {
6399 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6400 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006401 ASSERT(result ==
6402 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006403 return result;
6404}
6405
6406
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006407RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006408 NoHandleAllocation ha;
6409 ASSERT(args.length() == 2);
6410
6411 CONVERT_CHECKED(String, x, args[0]);
6412 CONVERT_CHECKED(String, y, args[1]);
6413
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006414 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006415
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006416 // A few fast case tests before we flatten.
6417 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006418 if (y->length() == 0) {
6419 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006420 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006421 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006422 return Smi::FromInt(LESS);
6423 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006424
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006425 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006426 if (d < 0) return Smi::FromInt(LESS);
6427 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006428
lrn@chromium.org303ada72010-10-27 09:33:13 +00006429 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006430 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006431 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6432 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006433 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006434 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6435 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006436
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006437 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006438 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006439}
6440
6441
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006442RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006443 NoHandleAllocation ha;
6444 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006445 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006446
6447 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006448 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006449}
6450
6451
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006452RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006453 NoHandleAllocation ha;
6454 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006455 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006456
6457 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006458 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006459}
6460
6461
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006462RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006463 NoHandleAllocation ha;
6464 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006465 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006466
6467 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006468 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006469}
6470
6471
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006472static const double kPiDividedBy4 = 0.78539816339744830962;
6473
6474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006475RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006476 NoHandleAllocation ha;
6477 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006478 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006479
6480 CONVERT_DOUBLE_CHECKED(x, args[0]);
6481 CONVERT_DOUBLE_CHECKED(y, args[1]);
6482 double result;
6483 if (isinf(x) && isinf(y)) {
6484 // Make sure that the result in case of two infinite arguments
6485 // is a multiple of Pi / 4. The sign of the result is determined
6486 // by the first argument (x) and the sign of the second argument
6487 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006488 int multiplier = (x < 0) ? -1 : 1;
6489 if (y < 0) multiplier *= 3;
6490 result = multiplier * kPiDividedBy4;
6491 } else {
6492 result = atan2(x, y);
6493 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006494 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006495}
6496
6497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006498RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006499 NoHandleAllocation ha;
6500 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006501 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006502
6503 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006504 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006505}
6506
6507
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006508RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006509 NoHandleAllocation ha;
6510 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006511 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006512
6513 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006514 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006515}
6516
6517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006518RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006519 NoHandleAllocation ha;
6520 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006521 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006522
6523 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006524 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006525}
6526
6527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006528RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006529 NoHandleAllocation ha;
6530 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006531 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006532
6533 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006534 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006535}
6536
6537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006538RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006539 NoHandleAllocation ha;
6540 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006541 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006542
6543 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006544 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006545}
6546
6547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006548RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006549 NoHandleAllocation ha;
6550 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006551 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006552
6553 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006554
6555 // If the second argument is a smi, it is much faster to call the
6556 // custom powi() function than the generic pow().
6557 if (args[1]->IsSmi()) {
6558 int y = Smi::cast(args[1])->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006559 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006560 }
6561
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006562 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006563 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006564}
6565
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006566// Fast version of Math.pow if we know that y is not an integer and
6567// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006568RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006569 NoHandleAllocation ha;
6570 ASSERT(args.length() == 2);
6571 CONVERT_DOUBLE_CHECKED(x, args[0]);
6572 CONVERT_DOUBLE_CHECKED(y, args[1]);
6573 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006574 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006575 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006576 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006577 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006578 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006579 }
6580}
6581
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006582
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006583RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006584 NoHandleAllocation ha;
6585 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006586 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006588 if (!args[0]->IsHeapNumber()) {
6589 // Must be smi. Return the argument unchanged for all the other types
6590 // to make fuzz-natives test happy.
6591 return args[0];
6592 }
6593
6594 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6595
6596 double value = number->value();
6597 int exponent = number->get_exponent();
6598 int sign = number->get_sign();
6599
6600 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6601 // should be rounded to 2^30, which is not smi.
6602 if (!sign && exponent <= kSmiValueSize - 3) {
6603 return Smi::FromInt(static_cast<int>(value + 0.5));
6604 }
6605
6606 // If the magnitude is big enough, there's no place for fraction part. If we
6607 // try to add 0.5 to this number, 1.0 will be added instead.
6608 if (exponent >= 52) {
6609 return number;
6610 }
6611
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006612 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006613
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006614 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006615 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006616}
6617
6618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006619RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006620 NoHandleAllocation ha;
6621 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006622 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006623
6624 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006625 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006626}
6627
6628
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006629RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006630 NoHandleAllocation ha;
6631 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006632 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633
6634 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006635 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006636}
6637
6638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006639RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006640 NoHandleAllocation ha;
6641 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006642 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006643
6644 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006645 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006646}
6647
6648
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006649static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006650 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6651 181, 212, 243, 273, 304, 334};
6652 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6653 182, 213, 244, 274, 305, 335};
6654
6655 year += month / 12;
6656 month %= 12;
6657 if (month < 0) {
6658 year--;
6659 month += 12;
6660 }
6661
6662 ASSERT(month >= 0);
6663 ASSERT(month < 12);
6664
6665 // year_delta is an arbitrary number such that:
6666 // a) year_delta = -1 (mod 400)
6667 // b) year + year_delta > 0 for years in the range defined by
6668 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6669 // Jan 1 1970. This is required so that we don't run into integer
6670 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006671 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006672 // operations.
6673 static const int year_delta = 399999;
6674 static const int base_day = 365 * (1970 + year_delta) +
6675 (1970 + year_delta) / 4 -
6676 (1970 + year_delta) / 100 +
6677 (1970 + year_delta) / 400;
6678
6679 int year1 = year + year_delta;
6680 int day_from_year = 365 * year1 +
6681 year1 / 4 -
6682 year1 / 100 +
6683 year1 / 400 -
6684 base_day;
6685
6686 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006687 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006688 }
6689
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006690 return day_from_year + day_from_month_leap[month] + day - 1;
6691}
6692
6693
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006694RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006695 NoHandleAllocation ha;
6696 ASSERT(args.length() == 3);
6697
6698 CONVERT_SMI_CHECKED(year, args[0]);
6699 CONVERT_SMI_CHECKED(month, args[1]);
6700 CONVERT_SMI_CHECKED(date, args[2]);
6701
6702 return Smi::FromInt(MakeDay(year, month, date));
6703}
6704
6705
6706static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6707static const int kDaysIn4Years = 4 * 365 + 1;
6708static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6709static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6710static const int kDays1970to2000 = 30 * 365 + 7;
6711static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6712 kDays1970to2000;
6713static const int kYearsOffset = 400000;
6714
6715static const char kDayInYear[] = {
6716 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6717 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6718 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6719 22, 23, 24, 25, 26, 27, 28,
6720 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6721 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6722 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6723 22, 23, 24, 25, 26, 27, 28, 29, 30,
6724 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6725 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6726 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6727 22, 23, 24, 25, 26, 27, 28, 29, 30,
6728 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6729 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6730 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6731 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6732 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6733 22, 23, 24, 25, 26, 27, 28, 29, 30,
6734 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6735 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6736 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6737 22, 23, 24, 25, 26, 27, 28, 29, 30,
6738 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6739 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6740
6741 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6742 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6743 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6744 22, 23, 24, 25, 26, 27, 28,
6745 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6746 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6747 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6748 22, 23, 24, 25, 26, 27, 28, 29, 30,
6749 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6750 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6751 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6752 22, 23, 24, 25, 26, 27, 28, 29, 30,
6753 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6754 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6755 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6756 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6757 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6758 22, 23, 24, 25, 26, 27, 28, 29, 30,
6759 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6760 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6761 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6762 22, 23, 24, 25, 26, 27, 28, 29, 30,
6763 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6764 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6765
6766 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6767 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6768 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6769 22, 23, 24, 25, 26, 27, 28, 29,
6770 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6771 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6772 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6773 22, 23, 24, 25, 26, 27, 28, 29, 30,
6774 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6775 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6776 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6777 22, 23, 24, 25, 26, 27, 28, 29, 30,
6778 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6779 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6780 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6781 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6782 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6783 22, 23, 24, 25, 26, 27, 28, 29, 30,
6784 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6785 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6786 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6787 22, 23, 24, 25, 26, 27, 28, 29, 30,
6788 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6789 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6790
6791 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6792 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6793 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6794 22, 23, 24, 25, 26, 27, 28,
6795 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6796 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6797 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6798 22, 23, 24, 25, 26, 27, 28, 29, 30,
6799 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6800 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6801 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6802 22, 23, 24, 25, 26, 27, 28, 29, 30,
6803 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6804 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6805 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6806 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6807 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6808 22, 23, 24, 25, 26, 27, 28, 29, 30,
6809 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6810 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6811 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6812 22, 23, 24, 25, 26, 27, 28, 29, 30,
6813 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6814 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6815
6816static const char kMonthInYear[] = {
6817 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,
6818 0, 0, 0, 0, 0, 0,
6819 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,
6820 1, 1, 1,
6821 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,
6822 2, 2, 2, 2, 2, 2,
6823 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,
6824 3, 3, 3, 3, 3,
6825 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,
6826 4, 4, 4, 4, 4, 4,
6827 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,
6828 5, 5, 5, 5, 5,
6829 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,
6830 6, 6, 6, 6, 6, 6,
6831 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,
6832 7, 7, 7, 7, 7, 7,
6833 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,
6834 8, 8, 8, 8, 8,
6835 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,
6836 9, 9, 9, 9, 9, 9,
6837 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6838 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6839 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6840 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6841
6842 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,
6843 0, 0, 0, 0, 0, 0,
6844 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,
6845 1, 1, 1,
6846 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,
6847 2, 2, 2, 2, 2, 2,
6848 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,
6849 3, 3, 3, 3, 3,
6850 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,
6851 4, 4, 4, 4, 4, 4,
6852 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,
6853 5, 5, 5, 5, 5,
6854 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,
6855 6, 6, 6, 6, 6, 6,
6856 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,
6857 7, 7, 7, 7, 7, 7,
6858 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,
6859 8, 8, 8, 8, 8,
6860 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,
6861 9, 9, 9, 9, 9, 9,
6862 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6863 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6864 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6865 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6866
6867 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,
6868 0, 0, 0, 0, 0, 0,
6869 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,
6870 1, 1, 1, 1,
6871 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,
6872 2, 2, 2, 2, 2, 2,
6873 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,
6874 3, 3, 3, 3, 3,
6875 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,
6876 4, 4, 4, 4, 4, 4,
6877 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,
6878 5, 5, 5, 5, 5,
6879 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,
6880 6, 6, 6, 6, 6, 6,
6881 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,
6882 7, 7, 7, 7, 7, 7,
6883 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,
6884 8, 8, 8, 8, 8,
6885 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,
6886 9, 9, 9, 9, 9, 9,
6887 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6888 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6889 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6890 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6891
6892 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,
6893 0, 0, 0, 0, 0, 0,
6894 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,
6895 1, 1, 1,
6896 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,
6897 2, 2, 2, 2, 2, 2,
6898 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,
6899 3, 3, 3, 3, 3,
6900 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,
6901 4, 4, 4, 4, 4, 4,
6902 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,
6903 5, 5, 5, 5, 5,
6904 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,
6905 6, 6, 6, 6, 6, 6,
6906 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,
6907 7, 7, 7, 7, 7, 7,
6908 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,
6909 8, 8, 8, 8, 8,
6910 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,
6911 9, 9, 9, 9, 9, 9,
6912 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6913 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6914 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6915 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6916
6917
6918// This function works for dates from 1970 to 2099.
6919static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006920 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006921#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006922 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006923#endif
6924
6925 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6926 date %= kDaysIn4Years;
6927
6928 month = kMonthInYear[date];
6929 day = kDayInYear[date];
6930
6931 ASSERT(MakeDay(year, month, day) == save_date);
6932}
6933
6934
6935static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006936 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006937#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006938 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006939#endif
6940
6941 date += kDaysOffset;
6942 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6943 date %= kDaysIn400Years;
6944
6945 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6946
6947 date--;
6948 int yd1 = date / kDaysIn100Years;
6949 date %= kDaysIn100Years;
6950 year += 100 * yd1;
6951
6952 date++;
6953 int yd2 = date / kDaysIn4Years;
6954 date %= kDaysIn4Years;
6955 year += 4 * yd2;
6956
6957 date--;
6958 int yd3 = date / 365;
6959 date %= 365;
6960 year += yd3;
6961
6962 bool is_leap = (!yd1 || yd2) && !yd3;
6963
6964 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006965 ASSERT(is_leap || (date >= 0));
6966 ASSERT((date < 365) || (is_leap && (date < 366)));
6967 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6968 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6969 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006970
6971 if (is_leap) {
6972 day = kDayInYear[2*365 + 1 + date];
6973 month = kMonthInYear[2*365 + 1 + date];
6974 } else {
6975 day = kDayInYear[date];
6976 month = kMonthInYear[date];
6977 }
6978
6979 ASSERT(MakeDay(year, month, day) == save_date);
6980}
6981
6982
6983static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006984 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006985 if (date >= 0 && date < 32 * kDaysIn4Years) {
6986 DateYMDFromTimeAfter1970(date, year, month, day);
6987 } else {
6988 DateYMDFromTimeSlow(date, year, month, day);
6989 }
6990}
6991
6992
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006993RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006994 NoHandleAllocation ha;
6995 ASSERT(args.length() == 2);
6996
6997 CONVERT_DOUBLE_CHECKED(t, args[0]);
6998 CONVERT_CHECKED(JSArray, res_array, args[1]);
6999
7000 int year, month, day;
7001 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7002
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007003 RUNTIME_ASSERT(res_array->elements()->map() ==
7004 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007005 FixedArray* elms = FixedArray::cast(res_array->elements());
7006 RUNTIME_ASSERT(elms->length() == 3);
7007
7008 elms->set(0, Smi::FromInt(year));
7009 elms->set(1, Smi::FromInt(month));
7010 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007011
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007012 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007013}
7014
7015
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007016RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007017 NoHandleAllocation ha;
7018 ASSERT(args.length() == 3);
7019
7020 JSFunction* callee = JSFunction::cast(args[0]);
7021 Object** parameters = reinterpret_cast<Object**>(args[1]);
7022 const int length = Smi::cast(args[2])->value();
7023
lrn@chromium.org303ada72010-10-27 09:33:13 +00007024 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007025 { MaybeObject* maybe_result =
7026 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007027 if (!maybe_result->ToObject(&result)) return maybe_result;
7028 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007029 // Allocate the elements if needed.
7030 if (length > 0) {
7031 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007032 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007033 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007034 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7035 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007036
7037 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007038 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007039 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007040 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007041
7042 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007043 for (int i = 0; i < length; i++) {
7044 array->set(i, *--parameters, mode);
7045 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007046 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007047 }
7048 return result;
7049}
7050
7051
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007052RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007053 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007054 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007055 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007056 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007057 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007058
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007059 // Allocate global closures in old space and allocate local closures
7060 // in new space. Additionally pretenure closures that are assigned
7061 // directly to properties.
7062 pretenure = pretenure || (context->global_context() == *context);
7063 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007064 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007065 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7066 context,
7067 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068 return *result;
7069}
7070
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007071
7072static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7073 int* total_argc) {
7074 // Find frame containing arguments passed to the caller.
7075 JavaScriptFrameIterator it;
7076 JavaScriptFrame* frame = it.frame();
7077 List<JSFunction*> functions(2);
7078 frame->GetFunctions(&functions);
7079 if (functions.length() > 1) {
7080 int inlined_frame_index = functions.length() - 1;
7081 JSFunction* inlined_function = functions[inlined_frame_index];
7082 int args_count = inlined_function->shared()->formal_parameter_count();
7083 ScopedVector<SlotRef> args_slots(args_count);
7084 SlotRef::ComputeSlotMappingForArguments(frame,
7085 inlined_frame_index,
7086 &args_slots);
7087
7088 *total_argc = bound_argc + args_count;
7089 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7090 for (int i = 0; i < args_count; i++) {
7091 Handle<Object> val = args_slots[i].GetValue();
7092 param_data[bound_argc + i] = val.location();
7093 }
7094 return param_data;
7095 } else {
7096 it.AdvanceToArgumentsFrame();
7097 frame = it.frame();
7098 int args_count = frame->ComputeParametersCount();
7099
7100 *total_argc = bound_argc + args_count;
7101 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7102 for (int i = 0; i < args_count; i++) {
7103 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7104 param_data[bound_argc + i] = val.location();
7105 }
7106 return param_data;
7107 }
7108}
7109
7110
7111RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007112 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007113 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007114 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007115 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007116
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007117 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007118 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007119 int bound_argc = 0;
7120 if (!args[1]->IsNull()) {
7121 CONVERT_ARG_CHECKED(JSArray, params, 1);
7122 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007123 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007124 bound_argc = Smi::cast(params->length())->value();
7125 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007126
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007127 int total_argc = 0;
7128 SmartPointer<Object**> param_data =
7129 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007130 for (int i = 0; i < bound_argc; i++) {
7131 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007132 param_data[i] = val.location();
7133 }
7134
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007135 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007136 Handle<Object> result =
7137 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007138 if (exception) {
7139 return Failure::Exception();
7140 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007141
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007142 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007143 return *result;
7144}
7145
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007146
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007147static void TrySettingInlineConstructStub(Isolate* isolate,
7148 Handle<JSFunction> function) {
7149 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007150 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007151 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007152 }
7153 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007154 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007155 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007156 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007157 function->shared()->set_construct_stub(
7158 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007159 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007160 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007161}
7162
7163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007164RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007165 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007166 ASSERT(args.length() == 1);
7167
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007168 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007169
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007170 // If the constructor isn't a proper function we throw a type error.
7171 if (!constructor->IsJSFunction()) {
7172 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7173 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007174 isolate->factory()->NewTypeError("not_constructor", arguments);
7175 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007176 }
7177
7178 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007179
7180 // If function should not have prototype, construction is not allowed. In this
7181 // case generated code bailouts here, since function has no initial_map.
7182 if (!function->should_have_prototype()) {
7183 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7184 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007185 isolate->factory()->NewTypeError("not_constructor", arguments);
7186 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007187 }
7188
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007189#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007190 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007191 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007192 if (debug->StepInActive()) {
7193 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007194 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007195#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007196
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007197 if (function->has_initial_map()) {
7198 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007199 // The 'Function' function ignores the receiver object when
7200 // called using 'new' and creates a new JSFunction object that
7201 // is returned. The receiver object is only used for error
7202 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007203 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007204 // allocate JSFunctions since it does not properly initialize
7205 // the shared part of the function. Since the receiver is
7206 // ignored anyway, we use the global object as the receiver
7207 // instead of a new JSFunction object. This way, errors are
7208 // reported the same way whether or not 'Function' is called
7209 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007210 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007211 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007212 }
7213
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007214 // The function should be compiled for the optimization hints to be
7215 // available. We cannot use EnsureCompiled because that forces a
7216 // compilation through the shared function info which makes it
7217 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007218 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007219 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007220
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007221 if (!function->has_initial_map() &&
7222 shared->IsInobjectSlackTrackingInProgress()) {
7223 // The tracking is already in progress for another function. We can only
7224 // track one initial_map at a time, so we force the completion before the
7225 // function is called as a constructor for the first time.
7226 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007227 }
7228
7229 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007230 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7231 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007232 // Delay setting the stub if inobject slack tracking is in progress.
7233 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007234 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007235 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007236
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007237 isolate->counters()->constructed_objects()->Increment();
7238 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007239
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007240 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007241}
7242
7243
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007244RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007245 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007246 ASSERT(args.length() == 1);
7247
7248 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7249 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007250 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007251
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007252 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007253}
7254
7255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007256RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007257 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007258 ASSERT(args.length() == 1);
7259
7260 Handle<JSFunction> function = args.at<JSFunction>(0);
7261#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007262 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007263 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007264 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007265 PrintF("]\n");
7266 }
7267#endif
7268
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007269 // Compile the target function. Here we compile using CompileLazyInLoop in
7270 // order to get the optimized version. This helps code like delta-blue
7271 // that calls performance-critical routines through constructors. A
7272 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7273 // direct call. Since the in-loop tracking takes place through CallICs
7274 // this means that things called through constructors are never known to
7275 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007276 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007277 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007278 return Failure::Exception();
7279 }
7280
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007281 // All done. Return the compiled code.
7282 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007283 return function->code();
7284}
7285
7286
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007287RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007288 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007289 ASSERT(args.length() == 1);
7290 Handle<JSFunction> function = args.at<JSFunction>(0);
7291 // If the function is not optimizable or debugger is active continue using the
7292 // code from the full compiler.
7293 if (!function->shared()->code()->optimizable() ||
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007294 isolate->debug()->has_break_points()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007295 if (FLAG_trace_opt) {
7296 PrintF("[failed to optimize ");
7297 function->PrintName();
7298 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7299 function->shared()->code()->optimizable() ? "T" : "F",
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007300 isolate->debug()->has_break_points() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007301 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007302 function->ReplaceCode(function->shared()->code());
7303 return function->code();
7304 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007305 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007306 return function->code();
7307 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007308 if (FLAG_trace_opt) {
7309 PrintF("[failed to optimize ");
7310 function->PrintName();
7311 PrintF(": optimized compilation failed]\n");
7312 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007313 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007314 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007315}
7316
7317
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007318RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007319 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007320 ASSERT(args.length() == 1);
7321 RUNTIME_ASSERT(args[0]->IsSmi());
7322 Deoptimizer::BailoutType type =
7323 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007324 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7325 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007326 int frames = deoptimizer->output_count();
7327
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007328 deoptimizer->MaterializeHeapNumbers();
7329 delete deoptimizer;
7330
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007331 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007332 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007333 for (int i = 0; i < frames - 1; i++) it.Advance();
7334 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007335
7336 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007337 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007338 Handle<Object> arguments;
7339 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007340 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007341 if (arguments.is_null()) {
7342 // FunctionGetArguments can't throw an exception, so cast away the
7343 // doubt with an assert.
7344 arguments = Handle<Object>(
7345 Accessors::FunctionGetArguments(*function,
7346 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007347 ASSERT(*arguments != isolate->heap()->null_value());
7348 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007349 }
7350 frame->SetExpression(i, *arguments);
7351 }
7352 }
7353
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007354 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007355 if (type == Deoptimizer::EAGER) {
7356 RUNTIME_ASSERT(function->IsOptimized());
7357 } else {
7358 RUNTIME_ASSERT(!function->IsOptimized());
7359 }
7360
7361 // Avoid doing too much work when running with --always-opt and keep
7362 // the optimized code around.
7363 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007364 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007365 }
7366
7367 // Count the number of optimized activations of the function.
7368 int activations = 0;
7369 while (!it.done()) {
7370 JavaScriptFrame* frame = it.frame();
7371 if (frame->is_optimized() && frame->function() == *function) {
7372 activations++;
7373 }
7374 it.Advance();
7375 }
7376
7377 // TODO(kasperl): For now, we cannot support removing the optimized
7378 // code when we have recursive invocations of the same function.
7379 if (activations == 0) {
7380 if (FLAG_trace_deopt) {
7381 PrintF("[removing optimized code for: ");
7382 function->PrintName();
7383 PrintF("]\n");
7384 }
7385 function->ReplaceCode(function->shared()->code());
7386 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007387 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007388}
7389
7390
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007391RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007392 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007393 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007394 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007395}
7396
7397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007398RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007399 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007400 ASSERT(args.length() == 1);
7401 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007402 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007403
7404 Deoptimizer::DeoptimizeFunction(*function);
7405
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007406 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007407}
7408
7409
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007410RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7411 HandleScope scope(isolate);
7412 ASSERT(args.length() == 1);
7413 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7414 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7415 function->MarkForLazyRecompilation();
7416 return isolate->heap()->undefined_value();
7417}
7418
7419
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007420RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007421 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007422 ASSERT(args.length() == 1);
7423 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7424
7425 // We're not prepared to handle a function with arguments object.
7426 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7427
7428 // We have hit a back edge in an unoptimized frame for a function that was
7429 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007430 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007431 // Keep track of whether we've succeeded in optimizing.
7432 bool succeeded = unoptimized->optimizable();
7433 if (succeeded) {
7434 // If we are trying to do OSR when there are already optimized
7435 // activations of the function, it means (a) the function is directly or
7436 // indirectly recursive and (b) an optimized invocation has been
7437 // deoptimized so that we are currently in an unoptimized activation.
7438 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007439 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007440 while (succeeded && !it.done()) {
7441 JavaScriptFrame* frame = it.frame();
7442 succeeded = !frame->is_optimized() || frame->function() != *function;
7443 it.Advance();
7444 }
7445 }
7446
7447 int ast_id = AstNode::kNoNumber;
7448 if (succeeded) {
7449 // The top JS function is this one, the PC is somewhere in the
7450 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007451 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007452 JavaScriptFrame* frame = it.frame();
7453 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007454 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007455 ASSERT(unoptimized->contains(frame->pc()));
7456
7457 // Use linear search of the unoptimized code's stack check table to find
7458 // the AST id matching the PC.
7459 Address start = unoptimized->instruction_start();
7460 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007461 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007462 uint32_t table_length = Memory::uint32_at(table_cursor);
7463 table_cursor += kIntSize;
7464 for (unsigned i = 0; i < table_length; ++i) {
7465 // Table entries are (AST id, pc offset) pairs.
7466 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7467 if (pc_offset == target_pc_offset) {
7468 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7469 break;
7470 }
7471 table_cursor += 2 * kIntSize;
7472 }
7473 ASSERT(ast_id != AstNode::kNoNumber);
7474 if (FLAG_trace_osr) {
7475 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7476 function->PrintName();
7477 PrintF("]\n");
7478 }
7479
7480 // Try to compile the optimized code. A true return value from
7481 // CompileOptimized means that compilation succeeded, not necessarily
7482 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007483 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7484 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007485 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7486 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007487 if (data->OsrPcOffset()->value() >= 0) {
7488 if (FLAG_trace_osr) {
7489 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007490 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007491 }
7492 ASSERT(data->OsrAstId()->value() == ast_id);
7493 } else {
7494 // We may never generate the desired OSR entry if we emit an
7495 // early deoptimize.
7496 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007497 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007498 } else {
7499 succeeded = false;
7500 }
7501 }
7502
7503 // Revert to the original stack checks in the original unoptimized code.
7504 if (FLAG_trace_osr) {
7505 PrintF("[restoring original stack checks in ");
7506 function->PrintName();
7507 PrintF("]\n");
7508 }
7509 StackCheckStub check_stub;
7510 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007511 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007512 Deoptimizer::RevertStackCheckCode(*unoptimized,
7513 *check_code,
7514 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007515
7516 // Allow OSR only at nesting level zero again.
7517 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7518
7519 // If the optimization attempt succeeded, return the AST id tagged as a
7520 // smi. This tells the builtin that we need to translate the unoptimized
7521 // frame to an optimized one.
7522 if (succeeded) {
7523 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7524 return Smi::FromInt(ast_id);
7525 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007526 if (function->IsMarkedForLazyRecompilation()) {
7527 function->ReplaceCode(function->shared()->code());
7528 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007529 return Smi::FromInt(-1);
7530 }
7531}
7532
7533
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007534RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007535 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007536 ASSERT(args.length() == 1);
7537 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7538 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7539}
7540
7541
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007542RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007543 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007544 ASSERT(args.length() == 1);
7545 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7546 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7547}
7548
7549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007550RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007551 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007552 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007553
kasper.lund7276f142008-07-30 08:49:36 +00007554 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007555 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007556 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007557 { MaybeObject* maybe_result =
7558 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007559 if (!maybe_result->ToObject(&result)) return maybe_result;
7560 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007561
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007562 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007563
kasper.lund7276f142008-07-30 08:49:36 +00007564 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007565}
7566
lrn@chromium.org303ada72010-10-27 09:33:13 +00007567
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007568MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7569 Object* object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007570 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007571 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007572 Object* js_object = object;
7573 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007574 MaybeObject* maybe_js_object = js_object->ToObject();
7575 if (!maybe_js_object->ToObject(&js_object)) {
7576 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7577 return maybe_js_object;
7578 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007579 HandleScope scope(isolate);
7580 Handle<Object> handle(object, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007581 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007582 isolate->factory()->NewTypeError("with_expression",
7583 HandleVector(&handle, 1));
7584 return isolate->Throw(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007585 }
7586 }
7587
lrn@chromium.org303ada72010-10-27 09:33:13 +00007588 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007589 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7590 isolate->context(), JSObject::cast(js_object), is_catch_context);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007591 if (!maybe_result->ToObject(&result)) return maybe_result;
7592 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007593
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007594 Context* context = Context::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007595 isolate->set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007596
kasper.lund7276f142008-07-30 08:49:36 +00007597 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007598}
7599
7600
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007601RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007602 NoHandleAllocation ha;
7603 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007604 return PushContextHelper(isolate, args[0], false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007605}
7606
7607
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007608RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007609 NoHandleAllocation ha;
7610 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007611 return PushContextHelper(isolate, args[0], true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007612}
7613
7614
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007615RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007616 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007617 ASSERT(args.length() == 2);
7618
7619 CONVERT_ARG_CHECKED(Context, context, 0);
7620 CONVERT_ARG_CHECKED(String, name, 1);
7621
7622 int index;
7623 PropertyAttributes attributes;
7624 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007625 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007626
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007627 // If the slot was not found the result is true.
7628 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007629 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007630 }
7631
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007632 // If the slot was found in a context, it should be DONT_DELETE.
7633 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007634 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007635 }
7636
7637 // The slot was found in a JSObject, either a context extension object,
7638 // the global object, or an arguments object. Try to delete it
7639 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7640 // which allows deleting all parameters in functions that mention
7641 // 'arguments', we do this even for the case of slots found on an
7642 // arguments object. The slot was found on an arguments object if the
7643 // index is non-negative.
7644 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7645 if (index >= 0) {
7646 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7647 } else {
7648 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7649 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007650}
7651
7652
ager@chromium.orga1645e22009-09-09 19:27:10 +00007653// A mechanism to return a pair of Object pointers in registers (if possible).
7654// How this is achieved is calling convention-dependent.
7655// All currently supported x86 compiles uses calling conventions that are cdecl
7656// variants where a 64-bit value is returned in two 32-bit registers
7657// (edx:eax on ia32, r1:r0 on ARM).
7658// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7659// In Win64 calling convention, a struct of two pointers is returned in memory,
7660// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007661#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007662struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007663 MaybeObject* x;
7664 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007665};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007666
lrn@chromium.org303ada72010-10-27 09:33:13 +00007667static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007668 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007669 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7670 // In Win64 they are assigned to a hidden first argument.
7671 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007672}
7673#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007674typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007675static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007676 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007677 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007678}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007679#endif
7680
7681
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007682static inline MaybeObject* Unhole(Heap* heap,
7683 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007684 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007685 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7686 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007687 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007688}
7689
7690
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007691static JSObject* ComputeReceiverForNonGlobal(Isolate* isolate,
7692 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007693 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007694 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007695 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007696 JSFunction* context_extension_function =
7697 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007698 // If the holder isn't a context extension object, we just return it
7699 // as the receiver. This allows arguments objects to be used as
7700 // receivers, but only if they are put in the context scope chain
7701 // explicitly via a with-statement.
7702 Object* constructor = holder->map()->constructor();
7703 if (constructor != context_extension_function) return holder;
7704 // Fall back to using the global object as the receiver if the
7705 // property turns out to be a local variable allocated in a context
7706 // extension object - introduced via eval.
7707 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007708}
7709
7710
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007711static ObjectPair LoadContextSlotHelper(Arguments args,
7712 Isolate* isolate,
7713 bool throw_error) {
7714 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00007715 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007716
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007717 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007718 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007719 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007720 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007721 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007722
7723 int index;
7724 PropertyAttributes attributes;
7725 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007726 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007727
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007728 // If the index is non-negative, the slot has been found in a local
7729 // variable or a parameter. Read it from the context object or the
7730 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007731 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007732 // If the "property" we were looking for is a local variable or an
7733 // argument in a context, the receiver is the global object; see
7734 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007735 JSObject* receiver =
7736 isolate->context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007737 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007738 ? Context::cast(*holder)->get(index)
7739 : JSObject::cast(*holder)->GetElement(index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007740 return MakePair(Unhole(isolate->heap(), value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007741 }
7742
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007743 // If the holder is found, we read the property from it.
7744 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007745 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007746 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007747 JSObject* receiver;
7748 if (object->IsGlobalObject()) {
7749 receiver = GlobalObject::cast(object)->global_receiver();
7750 } else if (context->is_exception_holder(*holder)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007751 receiver = isolate->context()->global()->global_receiver();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007752 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007753 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007754 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007755 // No need to unhole the value here. This is taken care of by the
7756 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007757 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007758 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007759 }
7760
7761 if (throw_error) {
7762 // The property doesn't exist - throw exception.
7763 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007764 isolate->factory()->NewReferenceError("not_defined",
7765 HandleVector(&name, 1));
7766 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007767 } else {
7768 // The property doesn't exist - return undefined
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007769 return MakePair(isolate->heap()->undefined_value(),
7770 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007771 }
7772}
7773
7774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007775RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007776 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007777}
7778
7779
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007780RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007781 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007782}
7783
7784
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007785RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007786 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007787 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007788
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007789 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007790 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007791 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007792 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
7793 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
7794 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007795 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007796
7797 int index;
7798 PropertyAttributes attributes;
7799 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007800 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007801
7802 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007803 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007804 // Ignore if read_only variable.
7805 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007806 // Context is a fixed array and set cannot fail.
7807 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007808 } else if (strict_mode == kStrictMode) {
7809 // Setting read only property in strict mode.
7810 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007811 isolate->factory()->NewTypeError("strict_cannot_assign",
7812 HandleVector(&name, 1));
7813 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007814 }
7815 } else {
7816 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007817 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007818 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007819 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007820 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007821 return Failure::Exception();
7822 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007823 }
7824 return *value;
7825 }
7826
7827 // Slow case: The property is not in a FixedArray context.
7828 // It is either in an JSObject extension context or it was not found.
7829 Handle<JSObject> context_ext;
7830
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007831 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007832 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007833 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007834 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007835 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007836 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007837
7838 if (strict_mode == kStrictMode) {
7839 // Throw in strict mode (assignment to undefined variable).
7840 Handle<Object> error =
7841 isolate->factory()->NewReferenceError(
7842 "not_defined", HandleVector(&name, 1));
7843 return isolate->Throw(*error);
7844 }
7845 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007846 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007847 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007848 }
7849
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007850 // Set the property, but ignore if read_only variable on the context
7851 // extension object itself.
7852 if ((attributes & READ_ONLY) == 0 ||
7853 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007854 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007855 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007856 SetProperty(context_ext, name, value, NONE, strict_mode));
7857 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007858 // Setting read only property in strict mode.
7859 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007860 isolate->factory()->NewTypeError(
7861 "strict_cannot_assign", HandleVector(&name, 1));
7862 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007863 }
7864 return *value;
7865}
7866
7867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007868RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007869 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007870 ASSERT(args.length() == 1);
7871
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007872 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007873}
7874
7875
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007876RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007877 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007878 ASSERT(args.length() == 1);
7879
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007880 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007881}
7882
7883
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007884RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007885 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007886 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007887}
7888
7889
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007890RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007891 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007892 ASSERT(args.length() == 1);
7893
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007894 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007895 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007896 isolate->factory()->NewReferenceError("not_defined",
7897 HandleVector(&name, 1));
7898 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007899}
7900
7901
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007902RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007903 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007904
7905 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007906 if (isolate->stack_guard()->IsStackOverflow()) {
7907 NoHandleAllocation na;
7908 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007909 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007910
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007911 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007912}
7913
7914
7915// NOTE: These PrintXXX functions are defined for all builds (not just
7916// DEBUG builds) because we may want to be able to trace function
7917// calls in all modes.
7918static void PrintString(String* str) {
7919 // not uncommon to have empty strings
7920 if (str->length() > 0) {
7921 SmartPointer<char> s =
7922 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7923 PrintF("%s", *s);
7924 }
7925}
7926
7927
7928static void PrintObject(Object* obj) {
7929 if (obj->IsSmi()) {
7930 PrintF("%d", Smi::cast(obj)->value());
7931 } else if (obj->IsString() || obj->IsSymbol()) {
7932 PrintString(String::cast(obj));
7933 } else if (obj->IsNumber()) {
7934 PrintF("%g", obj->Number());
7935 } else if (obj->IsFailure()) {
7936 PrintF("<failure>");
7937 } else if (obj->IsUndefined()) {
7938 PrintF("<undefined>");
7939 } else if (obj->IsNull()) {
7940 PrintF("<null>");
7941 } else if (obj->IsTrue()) {
7942 PrintF("<true>");
7943 } else if (obj->IsFalse()) {
7944 PrintF("<false>");
7945 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007946 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007947 }
7948}
7949
7950
7951static int StackSize() {
7952 int n = 0;
7953 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7954 return n;
7955}
7956
7957
7958static void PrintTransition(Object* result) {
7959 // indentation
7960 { const int nmax = 80;
7961 int n = StackSize();
7962 if (n <= nmax)
7963 PrintF("%4d:%*s", n, n, "");
7964 else
7965 PrintF("%4d:%*s", n, nmax, "...");
7966 }
7967
7968 if (result == NULL) {
7969 // constructor calls
7970 JavaScriptFrameIterator it;
7971 JavaScriptFrame* frame = it.frame();
7972 if (frame->IsConstructor()) PrintF("new ");
7973 // function name
7974 Object* fun = frame->function();
7975 if (fun->IsJSFunction()) {
7976 PrintObject(JSFunction::cast(fun)->shared()->name());
7977 } else {
7978 PrintObject(fun);
7979 }
7980 // function arguments
7981 // (we are intentionally only printing the actually
7982 // supplied parameters, not all parameters required)
7983 PrintF("(this=");
7984 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007985 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007986 for (int i = 0; i < length; i++) {
7987 PrintF(", ");
7988 PrintObject(frame->GetParameter(i));
7989 }
7990 PrintF(") {\n");
7991
7992 } else {
7993 // function result
7994 PrintF("} -> ");
7995 PrintObject(result);
7996 PrintF("\n");
7997 }
7998}
7999
8000
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008001RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008002 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008003 NoHandleAllocation ha;
8004 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008005 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008006}
8007
8008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008009RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008010 NoHandleAllocation ha;
8011 PrintTransition(args[0]);
8012 return args[0]; // return TOS
8013}
8014
8015
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008016RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008017 NoHandleAllocation ha;
8018 ASSERT(args.length() == 1);
8019
8020#ifdef DEBUG
8021 if (args[0]->IsString()) {
8022 // If we have a string, assume it's a code "marker"
8023 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008024 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008025 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008026 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8027 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008028 } else {
8029 PrintF("DebugPrint: ");
8030 }
8031 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008032 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008033 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008034 HeapObject::cast(args[0])->map()->Print();
8035 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008036#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008037 // ShortPrint is available in release mode. Print is not.
8038 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008039#endif
8040 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008041 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008042
8043 return args[0]; // return TOS
8044}
8045
8046
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008047RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008048 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008049 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008050 isolate->PrintStack();
8051 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008052}
8053
8054
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008055RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008056 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008057 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008058
8059 // According to ECMA-262, section 15.9.1, page 117, the precision of
8060 // the number in a Date object representing a particular instant in
8061 // time is milliseconds. Therefore, we floor the result of getting
8062 // the OS time.
8063 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008064 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008065}
8066
8067
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008068RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008069 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008070 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008071
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008072 CONVERT_ARG_CHECKED(String, str, 0);
8073 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008074
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008075 CONVERT_ARG_CHECKED(JSArray, output, 1);
8076 RUNTIME_ASSERT(output->HasFastElements());
8077
8078 AssertNoAllocation no_allocation;
8079
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008080 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008081 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8082 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008083 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008084 result = DateParser::Parse(str->ToAsciiVector(),
8085 output_array,
8086 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008087 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008088 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008089 result = DateParser::Parse(str->ToUC16Vector(),
8090 output_array,
8091 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008092 }
8093
8094 if (result) {
8095 return *output;
8096 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008097 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008098 }
8099}
8100
8101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008102RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008103 NoHandleAllocation ha;
8104 ASSERT(args.length() == 1);
8105
8106 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008107 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008108 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008109}
8110
8111
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008112RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008113 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008114 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008115
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008116 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008117}
8118
8119
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008120RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008121 NoHandleAllocation ha;
8122 ASSERT(args.length() == 1);
8123
8124 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008125 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008126}
8127
8128
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008129RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008130 ASSERT(args.length() == 1);
8131 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008132 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008133 return JSGlobalObject::cast(global)->global_receiver();
8134}
8135
8136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008137RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008138 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008139 ASSERT_EQ(1, args.length());
8140 CONVERT_ARG_CHECKED(String, source, 0);
8141
8142 Handle<Object> result = JsonParser::Parse(source);
8143 if (result.is_null()) {
8144 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008145 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008146 return Failure::Exception();
8147 }
8148 return *result;
8149}
8150
8151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008152RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008153 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008154 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008155 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008156
ager@chromium.org381abbb2009-02-25 13:23:22 +00008157 // Compile source string in the global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008158 Handle<Context> context(isolate->context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008159 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8160 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008161 true,
8162 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008163 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008164 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008165 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8166 context,
8167 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008168 return *fun;
8169}
8170
8171
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008172static ObjectPair CompileGlobalEval(Isolate* isolate,
8173 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008174 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008175 StrictModeFlag strict_mode) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008176 // Deal with a normal eval call with a string argument. Compile it
8177 // and return the compiled function bound in the local context.
8178 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8179 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008180 Handle<Context>(isolate->context()),
8181 isolate->context()->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008182 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008183 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008184 Handle<JSFunction> compiled =
8185 isolate->factory()->NewFunctionFromSharedFunctionInfo(
8186 shared, Handle<Context>(isolate->context()), NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008187 return MakePair(*compiled, *receiver);
8188}
8189
8190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008191RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008192 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008193
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008194 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008195 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008196 Handle<Object> receiver; // Will be overwritten.
8197
8198 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008199 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008200#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008201 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008202 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008203 StackFrameLocator locator;
8204 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008205 ASSERT(Context::cast(frame->context()) == *context);
8206#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008207
8208 // Find where the 'eval' symbol is bound. It is unaliased only if
8209 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008210 int index = -1;
8211 PropertyAttributes attributes = ABSENT;
8212 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008213 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8214 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008215 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008216 // Stop search when eval is found or when the global context is
8217 // reached.
8218 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008219 if (context->is_function_context()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008220 context = Handle<Context>(Context::cast(context->closure()->context()),
8221 isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008222 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008223 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008224 }
8225 }
8226
iposva@chromium.org245aa852009-02-10 00:49:54 +00008227 // If eval could not be resolved, it has been deleted and we need to
8228 // throw a reference error.
8229 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008230 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008231 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008232 isolate->factory()->NewReferenceError("not_defined",
8233 HandleVector(&name, 1));
8234 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008235 }
8236
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008237 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008238 // 'eval' is not bound in the global context. Just call the function
8239 // with the given arguments. This is not necessarily the global eval.
8240 if (receiver->IsContext()) {
8241 context = Handle<Context>::cast(receiver);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008242 receiver = Handle<Object>(context->get(index), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008243 } else if (receiver->IsJSContextExtensionObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008244 receiver = Handle<JSObject>(
8245 isolate->context()->global()->global_receiver(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008246 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008247 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008248 }
8249
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008250 // 'eval' is bound in the global context, but it may have been overwritten.
8251 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008252 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008253 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008254 return MakePair(*callee,
8255 isolate->context()->global()->global_receiver());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008256 }
8257
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008258 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008259 return CompileGlobalEval(isolate,
8260 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008261 args.at<Object>(2),
8262 static_cast<StrictModeFlag>(
8263 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008264}
8265
8266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008267RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008268 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008269
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008270 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008271 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008272
8273 // 'eval' is bound in the global context, but it may have been overwritten.
8274 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008275 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008276 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008277 return MakePair(*callee,
8278 isolate->context()->global()->global_receiver());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008279 }
8280
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008281 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008282 return CompileGlobalEval(isolate,
8283 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008284 args.at<Object>(2),
8285 static_cast<StrictModeFlag>(
8286 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008287}
8288
8289
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008290RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008291 // This utility adjusts the property attributes for newly created Function
8292 // object ("new Function(...)") by changing the map.
8293 // All it does is changing the prototype property to enumerable
8294 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008295 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008296 ASSERT(args.length() == 1);
8297 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008298
8299 Handle<Map> map = func->shared()->strict_mode()
8300 ? isolate->strict_mode_function_instance_map()
8301 : isolate->function_instance_map();
8302
8303 ASSERT(func->map()->instance_type() == map->instance_type());
8304 ASSERT(func->map()->instance_size() == map->instance_size());
8305 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008306 return *func;
8307}
8308
8309
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008310RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008311 // Allocate a block of memory in NewSpace (filled with a filler).
8312 // Use as fallback for allocation in generated code when NewSpace
8313 // is full.
8314 ASSERT(args.length() == 1);
8315 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8316 int size = size_smi->value();
8317 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8318 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008319 Heap* heap = isolate->heap();
8320 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008321 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008322 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008323 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008324 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008325 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008326 }
8327 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008328 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008329}
8330
8331
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008332// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008333// array. Returns true if the element was pushed on the stack and
8334// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008335RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008336 ASSERT(args.length() == 2);
8337 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008338 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008339 RUNTIME_ASSERT(array->HasFastElements());
8340 int length = Smi::cast(array->length())->value();
8341 FixedArray* elements = FixedArray::cast(array->elements());
8342 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008343 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008344 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008345 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008346 // Strict not needed. Used for cycle detection in Array join implementation.
8347 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8348 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008349 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8350 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008351 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008352}
8353
8354
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008355/**
8356 * A simple visitor visits every element of Array's.
8357 * The backend storage can be a fixed array for fast elements case,
8358 * or a dictionary for sparse array. Since Dictionary is a subtype
8359 * of FixedArray, the class can be used by both fast and slow cases.
8360 * The second parameter of the constructor, fast_elements, specifies
8361 * whether the storage is a FixedArray or Dictionary.
8362 *
8363 * An index limit is used to deal with the situation that a result array
8364 * length overflows 32-bit non-negative integer.
8365 */
8366class ArrayConcatVisitor {
8367 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008368 ArrayConcatVisitor(Isolate* isolate,
8369 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008370 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008371 isolate_(isolate),
8372 storage_(Handle<FixedArray>::cast(
8373 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008374 index_offset_(0u),
8375 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008376
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008377 ~ArrayConcatVisitor() {
8378 clear_storage();
8379 }
8380
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008381 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008382 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008383 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008384
8385 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008386 if (index < static_cast<uint32_t>(storage_->length())) {
8387 storage_->set(index, *elm);
8388 return;
8389 }
8390 // Our initial estimate of length was foiled, possibly by
8391 // getters on the arrays increasing the length of later arrays
8392 // during iteration.
8393 // This shouldn't happen in anything but pathological cases.
8394 SetDictionaryMode(index);
8395 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008396 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008397 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008398 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008399 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008400 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008401 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008402 // Dictionary needed to grow.
8403 clear_storage();
8404 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008405 }
8406}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008407
8408 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008409 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8410 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008411 } else {
8412 index_offset_ += delta;
8413 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008414 }
8415
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008416 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008417 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008418 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008419 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008420 Handle<Map> map;
8421 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008422 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008423 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008424 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008425 }
8426 array->set_map(*map);
8427 array->set_length(*length);
8428 array->set_elements(*storage_);
8429 return array;
8430 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008431
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008432 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008433 // Convert storage to dictionary mode.
8434 void SetDictionaryMode(uint32_t index) {
8435 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008436 Handle<FixedArray> current_storage(*storage_);
8437 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008438 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008439 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8440 for (uint32_t i = 0; i < current_length; i++) {
8441 HandleScope loop_scope;
8442 Handle<Object> element(current_storage->get(i));
8443 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008444 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008445 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008446 if (!new_storage.is_identical_to(slow_storage)) {
8447 slow_storage = loop_scope.CloseAndEscape(new_storage);
8448 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008449 }
8450 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008451 clear_storage();
8452 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008453 fast_elements_ = false;
8454 }
8455
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008456 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008457 isolate_->global_handles()->Destroy(
8458 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008459 }
8460
8461 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008462 storage_ = Handle<FixedArray>::cast(
8463 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008464 }
8465
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008466 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008467 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008468 // Index after last seen index. Always less than or equal to
8469 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008470 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008471 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008472};
8473
8474
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008475static uint32_t EstimateElementCount(Handle<JSArray> array) {
8476 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8477 int element_count = 0;
8478 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008479 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008480 // Fast elements can't have lengths that are not representable by
8481 // a 32-bit signed integer.
8482 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8483 int fast_length = static_cast<int>(length);
8484 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8485 for (int i = 0; i < fast_length; i++) {
8486 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008487 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008488 break;
8489 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008490 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008491 Handle<NumberDictionary> dictionary(
8492 NumberDictionary::cast(array->elements()));
8493 int capacity = dictionary->Capacity();
8494 for (int i = 0; i < capacity; i++) {
8495 Handle<Object> key(dictionary->KeyAt(i));
8496 if (dictionary->IsKey(*key)) {
8497 element_count++;
8498 }
8499 }
8500 break;
8501 }
8502 default:
8503 // External arrays are always dense.
8504 return length;
8505 }
8506 // As an estimate, we assume that the prototype doesn't contain any
8507 // inherited elements.
8508 return element_count;
8509}
8510
8511
8512
8513template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008514static void IterateExternalArrayElements(Isolate* isolate,
8515 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008516 bool elements_are_ints,
8517 bool elements_are_guaranteed_smis,
8518 ArrayConcatVisitor* visitor) {
8519 Handle<ExternalArrayClass> array(
8520 ExternalArrayClass::cast(receiver->elements()));
8521 uint32_t len = static_cast<uint32_t>(array->length());
8522
8523 ASSERT(visitor != NULL);
8524 if (elements_are_ints) {
8525 if (elements_are_guaranteed_smis) {
8526 for (uint32_t j = 0; j < len; j++) {
8527 HandleScope loop_scope;
8528 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8529 visitor->visit(j, e);
8530 }
8531 } else {
8532 for (uint32_t j = 0; j < len; j++) {
8533 HandleScope loop_scope;
8534 int64_t val = static_cast<int64_t>(array->get(j));
8535 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8536 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8537 visitor->visit(j, e);
8538 } else {
8539 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008540 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008541 visitor->visit(j, e);
8542 }
8543 }
8544 }
8545 } else {
8546 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008547 HandleScope loop_scope(isolate);
8548 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008549 visitor->visit(j, e);
8550 }
8551 }
8552}
8553
8554
8555// Used for sorting indices in a List<uint32_t>.
8556static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8557 uint32_t a = *ap;
8558 uint32_t b = *bp;
8559 return (a == b) ? 0 : (a < b) ? -1 : 1;
8560}
8561
8562
8563static void CollectElementIndices(Handle<JSObject> object,
8564 uint32_t range,
8565 List<uint32_t>* indices) {
8566 JSObject::ElementsKind kind = object->GetElementsKind();
8567 switch (kind) {
8568 case JSObject::FAST_ELEMENTS: {
8569 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8570 uint32_t length = static_cast<uint32_t>(elements->length());
8571 if (range < length) length = range;
8572 for (uint32_t i = 0; i < length; i++) {
8573 if (!elements->get(i)->IsTheHole()) {
8574 indices->Add(i);
8575 }
8576 }
8577 break;
8578 }
8579 case JSObject::DICTIONARY_ELEMENTS: {
8580 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008581 uint32_t capacity = dict->Capacity();
8582 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008583 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008584 Handle<Object> k(dict->KeyAt(j));
8585 if (dict->IsKey(*k)) {
8586 ASSERT(k->IsNumber());
8587 uint32_t index = static_cast<uint32_t>(k->Number());
8588 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008589 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008590 }
8591 }
8592 }
8593 break;
8594 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008595 default: {
8596 int dense_elements_length;
8597 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008598 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008599 dense_elements_length =
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008600 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008601 break;
8602 }
8603 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8604 dense_elements_length =
8605 ExternalByteArray::cast(object->elements())->length();
8606 break;
8607 }
8608 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8609 dense_elements_length =
8610 ExternalUnsignedByteArray::cast(object->elements())->length();
8611 break;
8612 }
8613 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8614 dense_elements_length =
8615 ExternalShortArray::cast(object->elements())->length();
8616 break;
8617 }
8618 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8619 dense_elements_length =
8620 ExternalUnsignedShortArray::cast(object->elements())->length();
8621 break;
8622 }
8623 case JSObject::EXTERNAL_INT_ELEMENTS: {
8624 dense_elements_length =
8625 ExternalIntArray::cast(object->elements())->length();
8626 break;
8627 }
8628 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8629 dense_elements_length =
8630 ExternalUnsignedIntArray::cast(object->elements())->length();
8631 break;
8632 }
8633 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8634 dense_elements_length =
8635 ExternalFloatArray::cast(object->elements())->length();
8636 break;
8637 }
8638 default:
8639 UNREACHABLE();
8640 dense_elements_length = 0;
8641 break;
8642 }
8643 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8644 if (range <= length) {
8645 length = range;
8646 // We will add all indices, so we might as well clear it first
8647 // and avoid duplicates.
8648 indices->Clear();
8649 }
8650 for (uint32_t i = 0; i < length; i++) {
8651 indices->Add(i);
8652 }
8653 if (length == range) return; // All indices accounted for already.
8654 break;
8655 }
8656 }
8657
8658 Handle<Object> prototype(object->GetPrototype());
8659 if (prototype->IsJSObject()) {
8660 // The prototype will usually have no inherited element indices,
8661 // but we have to check.
8662 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8663 }
8664}
8665
8666
8667/**
8668 * A helper function that visits elements of a JSArray in numerical
8669 * order.
8670 *
8671 * The visitor argument called for each existing element in the array
8672 * with the element index and the element's value.
8673 * Afterwards it increments the base-index of the visitor by the array
8674 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008675 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008676 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008677static bool IterateElements(Isolate* isolate,
8678 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008679 ArrayConcatVisitor* visitor) {
8680 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8681 switch (receiver->GetElementsKind()) {
8682 case JSObject::FAST_ELEMENTS: {
8683 // Run through the elements FixedArray and use HasElement and GetElement
8684 // to check the prototype for missing elements.
8685 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8686 int fast_length = static_cast<int>(length);
8687 ASSERT(fast_length <= elements->length());
8688 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008689 HandleScope loop_scope(isolate);
8690 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008691 if (!element_value->IsTheHole()) {
8692 visitor->visit(j, element_value);
8693 } else if (receiver->HasElement(j)) {
8694 // Call GetElement on receiver, not its prototype, or getters won't
8695 // have the correct receiver.
8696 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008697 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008698 visitor->visit(j, element_value);
8699 }
8700 }
8701 break;
8702 }
8703 case JSObject::DICTIONARY_ELEMENTS: {
8704 Handle<NumberDictionary> dict(receiver->element_dictionary());
8705 List<uint32_t> indices(dict->Capacity() / 2);
8706 // Collect all indices in the object and the prototypes less
8707 // than length. This might introduce duplicates in the indices list.
8708 CollectElementIndices(receiver, length, &indices);
8709 indices.Sort(&compareUInt32);
8710 int j = 0;
8711 int n = indices.length();
8712 while (j < n) {
8713 HandleScope loop_scope;
8714 uint32_t index = indices[j];
8715 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008716 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008717 visitor->visit(index, element);
8718 // Skip to next different index (i.e., omit duplicates).
8719 do {
8720 j++;
8721 } while (j < n && indices[j] == index);
8722 }
8723 break;
8724 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008725 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
8726 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
8727 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008728 for (uint32_t j = 0; j < length; j++) {
8729 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8730 visitor->visit(j, e);
8731 }
8732 break;
8733 }
8734 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8735 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008736 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008737 break;
8738 }
8739 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8740 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008741 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008742 break;
8743 }
8744 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8745 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008746 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008747 break;
8748 }
8749 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8750 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008751 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008752 break;
8753 }
8754 case JSObject::EXTERNAL_INT_ELEMENTS: {
8755 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008756 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008757 break;
8758 }
8759 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8760 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008761 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008762 break;
8763 }
8764 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8765 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008766 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008767 break;
8768 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008769 default:
8770 UNREACHABLE();
8771 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008772 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008773 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008774 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008775}
8776
8777
8778/**
8779 * Array::concat implementation.
8780 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008781 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008782 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008783 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008784RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008785 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008786 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008787
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008788 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8789 int argument_count = static_cast<int>(arguments->length()->Number());
8790 RUNTIME_ASSERT(arguments->HasFastElements());
8791 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008792
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008793 // Pass 1: estimate the length and number of elements of the result.
8794 // The actual length can be larger if any of the arguments have getters
8795 // that mutate other arguments (but will otherwise be precise).
8796 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008797
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008798 uint32_t estimate_result_length = 0;
8799 uint32_t estimate_nof_elements = 0;
8800 {
8801 for (int i = 0; i < argument_count; i++) {
8802 HandleScope loop_scope;
8803 Handle<Object> obj(elements->get(i));
8804 uint32_t length_estimate;
8805 uint32_t element_estimate;
8806 if (obj->IsJSArray()) {
8807 Handle<JSArray> array(Handle<JSArray>::cast(obj));
8808 length_estimate =
8809 static_cast<uint32_t>(array->length()->Number());
8810 element_estimate =
8811 EstimateElementCount(array);
8812 } else {
8813 length_estimate = 1;
8814 element_estimate = 1;
8815 }
8816 // Avoid overflows by capping at kMaxElementCount.
8817 if (JSObject::kMaxElementCount - estimate_result_length <
8818 length_estimate) {
8819 estimate_result_length = JSObject::kMaxElementCount;
8820 } else {
8821 estimate_result_length += length_estimate;
8822 }
8823 if (JSObject::kMaxElementCount - estimate_nof_elements <
8824 element_estimate) {
8825 estimate_nof_elements = JSObject::kMaxElementCount;
8826 } else {
8827 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008828 }
8829 }
8830 }
8831
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008832 // If estimated number of elements is more than half of length, a
8833 // fixed array (fast case) is more time and space-efficient than a
8834 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008835 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008836
8837 Handle<FixedArray> storage;
8838 if (fast_case) {
8839 // The backing storage array must have non-existing elements to
8840 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008841 storage = isolate->factory()->NewFixedArrayWithHoles(
8842 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008843 } else {
8844 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8845 uint32_t at_least_space_for = estimate_nof_elements +
8846 (estimate_nof_elements >> 2);
8847 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008848 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008849 }
8850
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008851 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008852
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008853 for (int i = 0; i < argument_count; i++) {
8854 Handle<Object> obj(elements->get(i));
8855 if (obj->IsJSArray()) {
8856 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008857 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008858 return Failure::Exception();
8859 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008860 } else {
8861 visitor.visit(0, obj);
8862 visitor.increase_index_offset(1);
8863 }
8864 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008865
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008866 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008867}
8868
8869
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008870// This will not allocate (flatten the string), but it may run
8871// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008872RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008873 NoHandleAllocation ha;
8874 ASSERT(args.length() == 1);
8875
8876 CONVERT_CHECKED(String, string, args[0]);
8877 StringInputBuffer buffer(string);
8878 while (buffer.has_more()) {
8879 uint16_t character = buffer.GetNext();
8880 PrintF("%c", character);
8881 }
8882 return string;
8883}
8884
ager@chromium.org5ec48922009-05-05 07:25:34 +00008885// Moves all own elements of an object, that are below a limit, to positions
8886// starting at zero. All undefined values are placed after non-undefined values,
8887// and are followed by non-existing element. Does not change the length
8888// property.
8889// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008890RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008891 ASSERT(args.length() == 2);
8892 CONVERT_CHECKED(JSObject, object, args[0]);
8893 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8894 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008895}
8896
8897
8898// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008899RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008900 ASSERT(args.length() == 2);
8901 CONVERT_CHECKED(JSArray, from, args[0]);
8902 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008903 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008904 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008905 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
8906 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008907 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008908 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008909 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008910 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008911 Object* new_map;
8912 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008913 to->set_map(Map::cast(new_map));
8914 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008915 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008916 Object* obj;
8917 { MaybeObject* maybe_obj = from->ResetElements();
8918 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8919 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008920 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008921 return to;
8922}
8923
8924
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008925// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008926RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008927 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008928 CONVERT_CHECKED(JSObject, object, args[0]);
8929 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008930 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008931 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008932 } else if (object->IsJSArray()) {
8933 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008934 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008935 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008936 }
8937}
8938
8939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008940RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008941 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008942
8943 ASSERT_EQ(3, args.length());
8944
ager@chromium.orgac091b72010-05-05 07:34:42 +00008945 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008946 Handle<Object> key1 = args.at<Object>(1);
8947 Handle<Object> key2 = args.at<Object>(2);
8948
8949 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008950 if (!key1->ToArrayIndex(&index1)
8951 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008952 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008953 }
8954
ager@chromium.orgac091b72010-05-05 07:34:42 +00008955 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8956 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008957 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00008958 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008959 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00008960
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008961 RETURN_IF_EMPTY_HANDLE(isolate,
8962 SetElement(jsobject, index1, tmp2, kStrictMode));
8963 RETURN_IF_EMPTY_HANDLE(isolate,
8964 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00008965
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008966 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008967}
8968
8969
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008970// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008971// might have elements. Can either return keys (positive integers) or
8972// intervals (pair of a negative integer (-start-1) followed by a
8973// positive (length)) or undefined values.
8974// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008975RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008976 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008977 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00008978 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008979 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008980 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008981 // Create an array and get all the keys into it, then remove all the
8982 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008983 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008984 int keys_length = keys->length();
8985 for (int i = 0; i < keys_length; i++) {
8986 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008987 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008988 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008989 // Zap invalid keys.
8990 keys->set_undefined(i);
8991 }
8992 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008993 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008994 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008995 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008996 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008997 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008998 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008999 uint32_t actual_length =
9000 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009001 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009002 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009003 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009004 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009005 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009006 }
9007}
9008
9009
9010// DefineAccessor takes an optional final argument which is the
9011// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9012// to the way accessors are implemented, it is set for both the getter
9013// and setter on the first call to DefineAccessor and ignored on
9014// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009015RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009016 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9017 // Compute attributes.
9018 PropertyAttributes attributes = NONE;
9019 if (args.length() == 5) {
9020 CONVERT_CHECKED(Smi, attrs, args[4]);
9021 int value = attrs->value();
9022 // Only attribute bits should be set.
9023 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9024 attributes = static_cast<PropertyAttributes>(value);
9025 }
9026
9027 CONVERT_CHECKED(JSObject, obj, args[0]);
9028 CONVERT_CHECKED(String, name, args[1]);
9029 CONVERT_CHECKED(Smi, flag, args[2]);
9030 CONVERT_CHECKED(JSFunction, fun, args[3]);
9031 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9032}
9033
9034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009035RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009036 ASSERT(args.length() == 3);
9037 CONVERT_CHECKED(JSObject, obj, args[0]);
9038 CONVERT_CHECKED(String, name, args[1]);
9039 CONVERT_CHECKED(Smi, flag, args[2]);
9040 return obj->LookupAccessor(name, flag->value() == 0);
9041}
9042
9043
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009044#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009045RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009046 ASSERT(args.length() == 0);
9047 return Execution::DebugBreakHelper();
9048}
9049
9050
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009051// Helper functions for wrapping and unwrapping stack frame ids.
9052static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009053 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009054 return Smi::FromInt(id >> 2);
9055}
9056
9057
9058static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9059 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9060}
9061
9062
9063// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009064// args[0]: debug event listener function to set or null or undefined for
9065// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009066// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009067RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009068 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009069 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9070 args[0]->IsUndefined() ||
9071 args[0]->IsNull());
9072 Handle<Object> callback = args.at<Object>(0);
9073 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009074 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009075
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009076 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009077}
9078
9079
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009080RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009081 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009082 isolate->stack_guard()->DebugBreak();
9083 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009084}
9085
9086
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009087static MaybeObject* DebugLookupResultValue(Heap* heap,
9088 Object* receiver,
9089 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009090 LookupResult* result,
9091 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009092 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009093 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009094 case NORMAL:
9095 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009096 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009097 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009098 }
9099 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009100 case FIELD:
9101 value =
9102 JSObject::cast(
9103 result->holder())->FastPropertyAt(result->GetFieldIndex());
9104 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009105 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009106 }
9107 return value;
9108 case CONSTANT_FUNCTION:
9109 return result->GetConstantFunction();
9110 case CALLBACKS: {
9111 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009112 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009113 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009114 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009115 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009116 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009117 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009118 maybe_value = heap->isolate()->pending_exception();
9119 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009120 if (caught_exception != NULL) {
9121 *caught_exception = true;
9122 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009123 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009124 }
9125 return value;
9126 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009127 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009128 }
9129 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009130 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009131 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009132 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009133 case CONSTANT_TRANSITION:
9134 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009135 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009136 default:
9137 UNREACHABLE();
9138 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009139 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009140 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009141}
9142
9143
ager@chromium.org32912102009-01-16 10:38:43 +00009144// Get debugger related details for an object property.
9145// args[0]: object holding property
9146// args[1]: name of the property
9147//
9148// The array returned contains the following information:
9149// 0: Property value
9150// 1: Property details
9151// 2: Property value is exception
9152// 3: Getter function if defined
9153// 4: Setter function if defined
9154// Items 2-4 are only filled if the property has either a getter or a setter
9155// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009156RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009157 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009158
9159 ASSERT(args.length() == 2);
9160
9161 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9162 CONVERT_ARG_CHECKED(String, name, 1);
9163
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009164 // Make sure to set the current context to the context before the debugger was
9165 // entered (if the debugger is entered). The reason for switching context here
9166 // is that for some property lookups (accessors and interceptors) callbacks
9167 // into the embedding application can occour, and the embedding application
9168 // could have the assumption that its own global context is the current
9169 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009170 SaveContext save(isolate);
9171 if (isolate->debug()->InDebugger()) {
9172 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009173 }
9174
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009175 // Skip the global proxy as it has no properties and always delegates to the
9176 // real global object.
9177 if (obj->IsJSGlobalProxy()) {
9178 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9179 }
9180
9181
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009182 // Check if the name is trivially convertible to an index and get the element
9183 // if so.
9184 uint32_t index;
9185 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009186 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009187 Object* element_or_char;
9188 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009189 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009190 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9191 return maybe_element_or_char;
9192 }
9193 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009194 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009195 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009196 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009197 }
9198
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009199 // Find the number of objects making up this.
9200 int length = LocalPrototypeChainLength(*obj);
9201
9202 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009203 Handle<JSObject> jsproto = obj;
9204 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009205 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009206 jsproto->LocalLookup(*name, &result);
9207 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009208 // LookupResult is not GC safe as it holds raw object pointers.
9209 // GC can happen later in this code so put the required fields into
9210 // local variables using handles when required for later use.
9211 PropertyType result_type = result.type();
9212 Handle<Object> result_callback_obj;
9213 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009214 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9215 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009216 }
9217 Smi* property_details = result.GetPropertyDetails().AsSmi();
9218 // DebugLookupResultValue can cause GC so details from LookupResult needs
9219 // to be copied to handles before this.
9220 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009221 Object* raw_value;
9222 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009223 DebugLookupResultValue(isolate->heap(), *obj, *name,
9224 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009225 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9226 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009227 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009228
9229 // If the callback object is a fixed array then it contains JavaScript
9230 // getter and/or setter.
9231 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9232 result_callback_obj->IsFixedArray();
9233 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009234 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009235 details->set(0, *value);
9236 details->set(1, property_details);
9237 if (hasJavaScriptAccessors) {
9238 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009239 caught_exception ? isolate->heap()->true_value()
9240 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009241 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9242 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9243 }
9244
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009245 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009246 }
9247 if (i < length - 1) {
9248 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9249 }
9250 }
9251
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009252 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009253}
9254
9255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009256RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009257 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009258
9259 ASSERT(args.length() == 2);
9260
9261 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9262 CONVERT_ARG_CHECKED(String, name, 1);
9263
9264 LookupResult result;
9265 obj->Lookup(*name, &result);
9266 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009267 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009268 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009269 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009270}
9271
9272
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009273// Return the property type calculated from the property details.
9274// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009275RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009276 ASSERT(args.length() == 1);
9277 CONVERT_CHECKED(Smi, details, args[0]);
9278 PropertyType type = PropertyDetails(details).type();
9279 return Smi::FromInt(static_cast<int>(type));
9280}
9281
9282
9283// Return the property attribute calculated from the property details.
9284// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009285RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009286 ASSERT(args.length() == 1);
9287 CONVERT_CHECKED(Smi, details, args[0]);
9288 PropertyAttributes attributes = PropertyDetails(details).attributes();
9289 return Smi::FromInt(static_cast<int>(attributes));
9290}
9291
9292
9293// Return the property insertion index calculated from the property details.
9294// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009295RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009296 ASSERT(args.length() == 1);
9297 CONVERT_CHECKED(Smi, details, args[0]);
9298 int index = PropertyDetails(details).index();
9299 return Smi::FromInt(index);
9300}
9301
9302
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009303// Return property value from named interceptor.
9304// args[0]: object
9305// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009306RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009307 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009308 ASSERT(args.length() == 2);
9309 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9310 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9311 CONVERT_ARG_CHECKED(String, name, 1);
9312
9313 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009314 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009315}
9316
9317
9318// Return element value from indexed interceptor.
9319// args[0]: object
9320// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009321RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009322 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009323 ASSERT(args.length() == 2);
9324 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9325 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9326 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9327
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009328 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009329}
9330
9331
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009332RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009333 ASSERT(args.length() >= 1);
9334 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009335 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009336 if (isolate->debug()->break_id() == 0 ||
9337 break_id != isolate->debug()->break_id()) {
9338 return isolate->Throw(
9339 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009340 }
9341
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009342 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009343}
9344
9345
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009346RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009347 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009348 ASSERT(args.length() == 1);
9349
9350 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009351 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009352 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9353 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009354 if (!maybe_result->ToObject(&result)) return maybe_result;
9355 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009356
9357 // Count all frames which are relevant to debugging stack trace.
9358 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009359 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009360 if (id == StackFrame::NO_ID) {
9361 // If there is no JavaScript stack frame count is 0.
9362 return Smi::FromInt(0);
9363 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009364 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009365 return Smi::FromInt(n);
9366}
9367
9368
9369static const int kFrameDetailsFrameIdIndex = 0;
9370static const int kFrameDetailsReceiverIndex = 1;
9371static const int kFrameDetailsFunctionIndex = 2;
9372static const int kFrameDetailsArgumentCountIndex = 3;
9373static const int kFrameDetailsLocalCountIndex = 4;
9374static const int kFrameDetailsSourcePositionIndex = 5;
9375static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009376static const int kFrameDetailsAtReturnIndex = 7;
9377static const int kFrameDetailsDebuggerFrameIndex = 8;
9378static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009379
9380// Return an array with frame details
9381// args[0]: number: break id
9382// args[1]: number: frame index
9383//
9384// The array returned contains the following information:
9385// 0: Frame id
9386// 1: Receiver
9387// 2: Function
9388// 3: Argument count
9389// 4: Local count
9390// 5: Source position
9391// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009392// 7: Is at return
9393// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009394// Arguments name, value
9395// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009396// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009397RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009398 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009399 ASSERT(args.length() == 2);
9400
9401 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009402 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009403 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9404 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009405 if (!maybe_check->ToObject(&check)) return maybe_check;
9406 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009407 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009408 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009409
9410 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009411 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009412 if (id == StackFrame::NO_ID) {
9413 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009414 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009415 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009416 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009417 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009418 for (; !it.done(); it.Advance()) {
9419 if (count == index) break;
9420 count++;
9421 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009422 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009423
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009424 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009425 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009426
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009427 // Traverse the saved contexts chain to find the active context for the
9428 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009429 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009430 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009431 save = save->prev();
9432 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009433 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009434
9435 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009436 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009437
9438 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009439 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009440 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009441
9442 // Check for constructor frame.
9443 bool constructor = it.frame()->IsConstructor();
9444
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009445 // Get scope info and read from it for local variable information.
9446 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009447 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009448 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009449
9450 // Get the context.
9451 Handle<Context> context(Context::cast(it.frame()->context()));
9452
9453 // Get the locals names and values into a temporary array.
9454 //
9455 // TODO(1240907): Hide compiler-introduced stack variables
9456 // (e.g. .result)? For users of the debugger, they will probably be
9457 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009458 Handle<FixedArray> locals =
9459 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009460
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009461 // Fill in the names of the locals.
9462 for (int i = 0; i < info.NumberOfLocals(); i++) {
9463 locals->set(i * 2, *info.LocalName(i));
9464 }
9465
9466 // Fill in the values of the locals.
9467 for (int i = 0; i < info.NumberOfLocals(); i++) {
9468 if (is_optimized_frame) {
9469 // If we are inspecting an optimized frame use undefined as the
9470 // value for all locals.
9471 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009472 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009473 // for locals in optimized frames.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009474 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009475 } else if (i < info.number_of_stack_slots()) {
9476 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009477 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9478 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009479 // Traverse the context chain to the function context as all local
9480 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009481 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009482 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009483 context = Handle<Context>(context->previous());
9484 }
9485 ASSERT(context->is_function_context());
9486 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009487 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009488 }
9489 }
9490
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009491 // Check whether this frame is positioned at return. If not top
9492 // frame or if the frame is optimized it cannot be at a return.
9493 bool at_return = false;
9494 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009495 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009496 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009497
9498 // If positioned just before return find the value to be returned and add it
9499 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009500 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009501 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009502 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009503 Address internal_frame_sp = NULL;
9504 while (!it2.done()) {
9505 if (it2.frame()->is_internal()) {
9506 internal_frame_sp = it2.frame()->sp();
9507 } else {
9508 if (it2.frame()->is_java_script()) {
9509 if (it2.frame()->id() == it.frame()->id()) {
9510 // The internal frame just before the JavaScript frame contains the
9511 // value to return on top. A debug break at return will create an
9512 // internal frame to store the return value (eax/rax/r0) before
9513 // entering the debug break exit frame.
9514 if (internal_frame_sp != NULL) {
9515 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009516 Handle<Object>(Memory::Object_at(internal_frame_sp),
9517 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009518 break;
9519 }
9520 }
9521 }
9522
9523 // Indicate that the previous frame was not an internal frame.
9524 internal_frame_sp = NULL;
9525 }
9526 it2.Advance();
9527 }
9528 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009529
9530 // Now advance to the arguments adapter frame (if any). It contains all
9531 // the provided parameters whereas the function frame always have the number
9532 // of arguments matching the functions parameters. The rest of the
9533 // information (except for what is collected above) is the same.
9534 it.AdvanceToArgumentsFrame();
9535
9536 // Find the number of arguments to fill. At least fill the number of
9537 // parameters for the function and fill more if more parameters are provided.
9538 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009539 if (argument_count < it.frame()->ComputeParametersCount()) {
9540 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009541 }
9542
9543 // Calculate the size of the result.
9544 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009545 2 * (argument_count + info.NumberOfLocals()) +
9546 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009547 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009548
9549 // Add the frame id.
9550 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9551
9552 // Add the function (same as in function frame).
9553 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9554
9555 // Add the arguments count.
9556 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9557
9558 // Add the locals count
9559 details->set(kFrameDetailsLocalCountIndex,
9560 Smi::FromInt(info.NumberOfLocals()));
9561
9562 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009563 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009564 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9565 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009566 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009567 }
9568
9569 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009570 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009571
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009572 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009573 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009574
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009575 // Add information on whether this frame is invoked in the debugger context.
9576 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009577 heap->ToBoolean(*save->context() ==
9578 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009579
9580 // Fill the dynamic part.
9581 int details_index = kFrameDetailsFirstDynamicIndex;
9582
9583 // Add arguments name and value.
9584 for (int i = 0; i < argument_count; i++) {
9585 // Name of the argument.
9586 if (i < info.number_of_parameters()) {
9587 details->set(details_index++, *info.parameter_name(i));
9588 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009589 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009590 }
9591
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009592 // Parameter value. If we are inspecting an optimized frame, use
9593 // undefined as the value.
9594 //
9595 // TODO(3141533): We should be able to get the actual parameter
9596 // value for optimized frames.
9597 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009598 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009599 details->set(details_index++, it.frame()->GetParameter(i));
9600 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009601 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009602 }
9603 }
9604
9605 // Add locals name and value from the temporary copy from the function frame.
9606 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9607 details->set(details_index++, locals->get(i));
9608 }
9609
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009610 // Add the value being returned.
9611 if (at_return) {
9612 details->set(details_index++, *return_value);
9613 }
9614
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009615 // Add the receiver (same as in function frame).
9616 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9617 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009618 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009619 if (!receiver->IsJSObject()) {
9620 // If the receiver is NOT a JSObject we have hit an optimization
9621 // where a value object is not converted into a wrapped JS objects.
9622 // To hide this optimization from the debugger, we wrap the receiver
9623 // by creating correct wrapper object based on the calling frame's
9624 // global context.
9625 it.Advance();
9626 Handle<Context> calling_frames_global_context(
9627 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009628 receiver =
9629 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009630 }
9631 details->set(kFrameDetailsReceiverIndex, *receiver);
9632
9633 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009634 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009635}
9636
9637
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009638// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009639static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009640 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009641 Handle<SerializedScopeInfo> serialized_scope_info,
9642 ScopeInfo<>& scope_info,
9643 Handle<Context> context,
9644 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009645 // Fill all context locals to the context extension.
9646 for (int i = Context::MIN_CONTEXT_SLOTS;
9647 i < scope_info.number_of_context_slots();
9648 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009649 int context_index = serialized_scope_info->ContextSlotIndex(
9650 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009651
9652 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009653 if (*scope_info.context_slot_name(i) !=
9654 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009655 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009656 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009657 SetProperty(scope_object,
9658 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009659 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009660 NONE,
9661 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009662 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009663 }
9664 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009665
9666 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009667}
9668
9669
9670// Create a plain JSObject which materializes the local scope for the specified
9671// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009672static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
9673 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009674 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009675 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009676 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9677 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009678
9679 // Allocate and initialize a JSObject with all the arguments, stack locals
9680 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009681 Handle<JSObject> local_scope =
9682 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009683
9684 // First fill all parameters.
9685 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009686 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009687 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009688 SetProperty(local_scope,
9689 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009690 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009691 NONE,
9692 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009693 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009694 }
9695
9696 // Second fill all stack locals.
9697 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009698 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009699 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009700 SetProperty(local_scope,
9701 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009702 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009703 NONE,
9704 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009705 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009706 }
9707
9708 // Third fill all context locals.
9709 Handle<Context> frame_context(Context::cast(frame->context()));
9710 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009711 if (!CopyContextLocalsToScopeObject(isolate,
9712 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009713 function_context, local_scope)) {
9714 return Handle<JSObject>();
9715 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009716
9717 // Finally copy any properties from the function context extension. This will
9718 // be variables introduced by eval.
9719 if (function_context->closure() == *function) {
9720 if (function_context->has_extension() &&
9721 !function_context->IsGlobalContext()) {
9722 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009723 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009724 for (int i = 0; i < keys->length(); i++) {
9725 // Names of variables introduced by eval are strings.
9726 ASSERT(keys->get(i)->IsString());
9727 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009728 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009729 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009730 SetProperty(local_scope,
9731 key,
9732 GetProperty(ext, key),
9733 NONE,
9734 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009735 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009736 }
9737 }
9738 }
9739 return local_scope;
9740}
9741
9742
9743// Create a plain JSObject which materializes the closure content for the
9744// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009745static Handle<JSObject> MaterializeClosure(Isolate* isolate,
9746 Handle<Context> context) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009747 ASSERT(context->is_function_context());
9748
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009749 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009750 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9751 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009752
9753 // Allocate and initialize a JSObject with all the content of theis function
9754 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009755 Handle<JSObject> closure_scope =
9756 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009757
9758 // Check whether the arguments shadow object exists.
9759 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009760 shared->scope_info()->ContextSlotIndex(
9761 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009762 if (arguments_shadow_index >= 0) {
9763 // In this case all the arguments are available in the arguments shadow
9764 // object.
9765 Handle<JSObject> arguments_shadow(
9766 JSObject::cast(context->get(arguments_shadow_index)));
9767 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009768 // We don't expect exception-throwing getters on the arguments shadow.
9769 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009770 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009771 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009772 SetProperty(closure_scope,
9773 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009774 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009775 NONE,
9776 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009777 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009778 }
9779 }
9780
9781 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009782 if (!CopyContextLocalsToScopeObject(isolate,
9783 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009784 context, closure_scope)) {
9785 return Handle<JSObject>();
9786 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009787
9788 // Finally copy any properties from the function context extension. This will
9789 // be variables introduced by eval.
9790 if (context->has_extension()) {
9791 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009792 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009793 for (int i = 0; i < keys->length(); i++) {
9794 // Names of variables introduced by eval are strings.
9795 ASSERT(keys->get(i)->IsString());
9796 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009797 RETURN_IF_EMPTY_HANDLE_VALUE(
9798 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009799 SetProperty(closure_scope,
9800 key,
9801 GetProperty(ext, key),
9802 NONE,
9803 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009804 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009805 }
9806 }
9807
9808 return closure_scope;
9809}
9810
9811
9812// Iterate over the actual scopes visible from a stack frame. All scopes are
9813// backed by an actual context except the local scope, which is inserted
9814// "artifically" in the context chain.
9815class ScopeIterator {
9816 public:
9817 enum ScopeType {
9818 ScopeTypeGlobal = 0,
9819 ScopeTypeLocal,
9820 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009821 ScopeTypeClosure,
9822 // Every catch block contains an implicit with block (its parameter is
9823 // a JSContextExtensionObject) that extends current scope with a variable
9824 // holding exception object. Such with blocks are treated as scopes of their
9825 // own type.
9826 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009827 };
9828
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009829 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
9830 : isolate_(isolate),
9831 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009832 function_(JSFunction::cast(frame->function())),
9833 context_(Context::cast(frame->context())),
9834 local_done_(false),
9835 at_local_(false) {
9836
9837 // Check whether the first scope is actually a local scope.
9838 if (context_->IsGlobalContext()) {
9839 // If there is a stack slot for .result then this local scope has been
9840 // created for evaluating top level code and it is not a real local scope.
9841 // Checking for the existence of .result seems fragile, but the scope info
9842 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009843 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009844 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009845 at_local_ = index < 0;
9846 } else if (context_->is_function_context()) {
9847 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009848 } else if (context_->closure() != *function_) {
9849 // The context_ is a with block from the outer function.
9850 ASSERT(context_->has_extension());
9851 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009852 }
9853 }
9854
9855 // More scopes?
9856 bool Done() { return context_.is_null(); }
9857
9858 // Move to the next scope.
9859 void Next() {
9860 // If at a local scope mark the local scope as passed.
9861 if (at_local_) {
9862 at_local_ = false;
9863 local_done_ = true;
9864
9865 // If the current context is not associated with the local scope the
9866 // current context is the next real scope, so don't move to the next
9867 // context in this case.
9868 if (context_->closure() != *function_) {
9869 return;
9870 }
9871 }
9872
9873 // The global scope is always the last in the chain.
9874 if (context_->IsGlobalContext()) {
9875 context_ = Handle<Context>();
9876 return;
9877 }
9878
9879 // Move to the next context.
9880 if (context_->is_function_context()) {
9881 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9882 } else {
9883 context_ = Handle<Context>(context_->previous());
9884 }
9885
9886 // If passing the local scope indicate that the current scope is now the
9887 // local scope.
9888 if (!local_done_ &&
9889 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9890 at_local_ = true;
9891 }
9892 }
9893
9894 // Return the type of the current scope.
9895 int Type() {
9896 if (at_local_) {
9897 return ScopeTypeLocal;
9898 }
9899 if (context_->IsGlobalContext()) {
9900 ASSERT(context_->global()->IsGlobalObject());
9901 return ScopeTypeGlobal;
9902 }
9903 if (context_->is_function_context()) {
9904 return ScopeTypeClosure;
9905 }
9906 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009907 // Current scope is either an explicit with statement or a with statement
9908 // implicitely generated for a catch block.
9909 // If the extension object here is a JSContextExtensionObject then
9910 // current with statement is one frome a catch block otherwise it's a
9911 // regular with statement.
9912 if (context_->extension()->IsJSContextExtensionObject()) {
9913 return ScopeTypeCatch;
9914 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009915 return ScopeTypeWith;
9916 }
9917
9918 // Return the JavaScript object with the content of the current scope.
9919 Handle<JSObject> ScopeObject() {
9920 switch (Type()) {
9921 case ScopeIterator::ScopeTypeGlobal:
9922 return Handle<JSObject>(CurrentContext()->global());
9923 break;
9924 case ScopeIterator::ScopeTypeLocal:
9925 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009926 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009927 break;
9928 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009929 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009930 // Return the with object.
9931 return Handle<JSObject>(CurrentContext()->extension());
9932 break;
9933 case ScopeIterator::ScopeTypeClosure:
9934 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009935 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009936 break;
9937 }
9938 UNREACHABLE();
9939 return Handle<JSObject>();
9940 }
9941
9942 // Return the context for this scope. For the local context there might not
9943 // be an actual context.
9944 Handle<Context> CurrentContext() {
9945 if (at_local_ && context_->closure() != *function_) {
9946 return Handle<Context>();
9947 }
9948 return context_;
9949 }
9950
9951#ifdef DEBUG
9952 // Debug print of the content of the current scope.
9953 void DebugPrint() {
9954 switch (Type()) {
9955 case ScopeIterator::ScopeTypeGlobal:
9956 PrintF("Global:\n");
9957 CurrentContext()->Print();
9958 break;
9959
9960 case ScopeIterator::ScopeTypeLocal: {
9961 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009962 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009963 scope_info.Print();
9964 if (!CurrentContext().is_null()) {
9965 CurrentContext()->Print();
9966 if (CurrentContext()->has_extension()) {
9967 Handle<JSObject> extension =
9968 Handle<JSObject>(CurrentContext()->extension());
9969 if (extension->IsJSContextExtensionObject()) {
9970 extension->Print();
9971 }
9972 }
9973 }
9974 break;
9975 }
9976
9977 case ScopeIterator::ScopeTypeWith: {
9978 PrintF("With:\n");
9979 Handle<JSObject> extension =
9980 Handle<JSObject>(CurrentContext()->extension());
9981 extension->Print();
9982 break;
9983 }
9984
ager@chromium.orga1645e22009-09-09 19:27:10 +00009985 case ScopeIterator::ScopeTypeCatch: {
9986 PrintF("Catch:\n");
9987 Handle<JSObject> extension =
9988 Handle<JSObject>(CurrentContext()->extension());
9989 extension->Print();
9990 break;
9991 }
9992
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009993 case ScopeIterator::ScopeTypeClosure: {
9994 PrintF("Closure:\n");
9995 CurrentContext()->Print();
9996 if (CurrentContext()->has_extension()) {
9997 Handle<JSObject> extension =
9998 Handle<JSObject>(CurrentContext()->extension());
9999 if (extension->IsJSContextExtensionObject()) {
10000 extension->Print();
10001 }
10002 }
10003 break;
10004 }
10005
10006 default:
10007 UNREACHABLE();
10008 }
10009 PrintF("\n");
10010 }
10011#endif
10012
10013 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010014 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010015 JavaScriptFrame* frame_;
10016 Handle<JSFunction> function_;
10017 Handle<Context> context_;
10018 bool local_done_;
10019 bool at_local_;
10020
10021 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10022};
10023
10024
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010025RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010026 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010027 ASSERT(args.length() == 2);
10028
10029 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010030 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010031 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10032 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010033 if (!maybe_check->ToObject(&check)) return maybe_check;
10034 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010035 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10036
10037 // Get the frame where the debugging is performed.
10038 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010039 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010040 JavaScriptFrame* frame = it.frame();
10041
10042 // Count the visible scopes.
10043 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010044 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010045 n++;
10046 }
10047
10048 return Smi::FromInt(n);
10049}
10050
10051
10052static const int kScopeDetailsTypeIndex = 0;
10053static const int kScopeDetailsObjectIndex = 1;
10054static const int kScopeDetailsSize = 2;
10055
10056// Return an array with scope details
10057// args[0]: number: break id
10058// args[1]: number: frame index
10059// args[2]: number: scope index
10060//
10061// The array returned contains the following information:
10062// 0: Scope type
10063// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010064RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010065 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010066 ASSERT(args.length() == 3);
10067
10068 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010069 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010070 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10071 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010072 if (!maybe_check->ToObject(&check)) return maybe_check;
10073 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010074 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10075 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10076
10077 // Get the frame where the debugging is performed.
10078 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010079 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010080 JavaScriptFrame* frame = frame_it.frame();
10081
10082 // Find the requested scope.
10083 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010084 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010085 for (; !it.Done() && n < index; it.Next()) {
10086 n++;
10087 }
10088 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010089 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010090 }
10091
10092 // Calculate the size of the result.
10093 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010094 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010095
10096 // Fill in scope details.
10097 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010098 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010099 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010100 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010101
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010102 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010103}
10104
10105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010106RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010107 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010108 ASSERT(args.length() == 0);
10109
10110#ifdef DEBUG
10111 // Print the scopes for the top frame.
10112 StackFrameLocator locator;
10113 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010114 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010115 it.DebugPrint();
10116 }
10117#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010118 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010119}
10120
10121
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010122RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010123 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010124 ASSERT(args.length() == 1);
10125
10126 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010127 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010128 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10129 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010130 if (!maybe_result->ToObject(&result)) return maybe_result;
10131 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010132
10133 // Count all archived V8 threads.
10134 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010135 for (ThreadState* thread =
10136 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010137 thread != NULL;
10138 thread = thread->Next()) {
10139 n++;
10140 }
10141
10142 // Total number of threads is current thread and archived threads.
10143 return Smi::FromInt(n + 1);
10144}
10145
10146
10147static const int kThreadDetailsCurrentThreadIndex = 0;
10148static const int kThreadDetailsThreadIdIndex = 1;
10149static const int kThreadDetailsSize = 2;
10150
10151// Return an array with thread details
10152// args[0]: number: break id
10153// args[1]: number: thread index
10154//
10155// The array returned contains the following information:
10156// 0: Is current thread?
10157// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010158RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010159 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010160 ASSERT(args.length() == 2);
10161
10162 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010163 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010164 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10165 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010166 if (!maybe_check->ToObject(&check)) return maybe_check;
10167 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010168 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10169
10170 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010171 Handle<FixedArray> details =
10172 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010173
10174 // Thread index 0 is current thread.
10175 if (index == 0) {
10176 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010177 details->set(kThreadDetailsCurrentThreadIndex,
10178 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010179 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010180 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010181 } else {
10182 // Find the thread with the requested index.
10183 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010184 ThreadState* thread =
10185 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010186 while (index != n && thread != NULL) {
10187 thread = thread->Next();
10188 n++;
10189 }
10190 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010191 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010192 }
10193
10194 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010195 details->set(kThreadDetailsCurrentThreadIndex,
10196 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010197 details->set(kThreadDetailsThreadIdIndex,
10198 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010199 }
10200
10201 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010202 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010203}
10204
10205
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010206// Sets the disable break state
10207// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010208RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010209 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010210 ASSERT(args.length() == 1);
10211 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010212 isolate->debug()->set_disable_break(disable_break);
10213 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010214}
10215
10216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010217RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010218 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010219 ASSERT(args.length() == 1);
10220
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010221 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10222 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010223 // Find the number of break points
10224 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010225 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010226 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010227 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010228 Handle<FixedArray>::cast(break_locations));
10229}
10230
10231
10232// Set a break point in a function
10233// args[0]: function
10234// args[1]: number: break source position (within the function source)
10235// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010236RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010237 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010238 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010239 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10240 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010241 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10242 RUNTIME_ASSERT(source_position >= 0);
10243 Handle<Object> break_point_object_arg = args.at<Object>(2);
10244
10245 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010246 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10247 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010248
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010249 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010250}
10251
10252
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010253Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10254 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010255 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010256 // Iterate the heap looking for SharedFunctionInfo generated from the
10257 // script. The inner most SharedFunctionInfo containing the source position
10258 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010259 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010260 // which is found is not compiled it is compiled and the heap is iterated
10261 // again as the compilation might create inner functions from the newly
10262 // compiled function and the actual requested break point might be in one of
10263 // these functions.
10264 bool done = false;
10265 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010266 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010267 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010268 while (!done) {
10269 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010270 for (HeapObject* obj = iterator.next();
10271 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010272 if (obj->IsSharedFunctionInfo()) {
10273 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10274 if (shared->script() == *script) {
10275 // If the SharedFunctionInfo found has the requested script data and
10276 // contains the source position it is a candidate.
10277 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010278 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010279 start_position = shared->start_position();
10280 }
10281 if (start_position <= position &&
10282 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010283 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010284 // candidate this is the new candidate.
10285 if (target.is_null()) {
10286 target_start_position = start_position;
10287 target = shared;
10288 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010289 if (target_start_position == start_position &&
10290 shared->end_position() == target->end_position()) {
10291 // If a top-level function contain only one function
10292 // declartion the source for the top-level and the function is
10293 // the same. In that case prefer the non top-level function.
10294 if (!shared->is_toplevel()) {
10295 target_start_position = start_position;
10296 target = shared;
10297 }
10298 } else if (target_start_position <= start_position &&
10299 shared->end_position() <= target->end_position()) {
10300 // This containment check includes equality as a function inside
10301 // a top-level function can share either start or end position
10302 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010303 target_start_position = start_position;
10304 target = shared;
10305 }
10306 }
10307 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010308 }
10309 }
10310 }
10311
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010312 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010313 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010314 }
10315
10316 // If the candidate found is compiled we are done. NOTE: when lazy
10317 // compilation of inner functions is introduced some additional checking
10318 // needs to be done here to compile inner functions.
10319 done = target->is_compiled();
10320 if (!done) {
10321 // If the candidate is not compiled compile it to reveal any inner
10322 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010323 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010324 }
10325 }
10326
10327 return *target;
10328}
10329
10330
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010331// Changes the state of a break point in a script and returns source position
10332// where break point was set. NOTE: Regarding performance see the NOTE for
10333// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010334// args[0]: script to set break point in
10335// args[1]: number: break source position (within the script source)
10336// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010337RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010338 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010339 ASSERT(args.length() == 3);
10340 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10341 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10342 RUNTIME_ASSERT(source_position >= 0);
10343 Handle<Object> break_point_object_arg = args.at<Object>(2);
10344
10345 // Get the script from the script wrapper.
10346 RUNTIME_ASSERT(wrapper->value()->IsScript());
10347 Handle<Script> script(Script::cast(wrapper->value()));
10348
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010349 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010350 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010351 if (!result->IsUndefined()) {
10352 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10353 // Find position within function. The script position might be before the
10354 // source position of the first function.
10355 int position;
10356 if (shared->start_position() > source_position) {
10357 position = 0;
10358 } else {
10359 position = source_position - shared->start_position();
10360 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010361 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010362 position += shared->start_position();
10363 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010364 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010365 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010366}
10367
10368
10369// Clear a break point
10370// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010371RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010372 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010373 ASSERT(args.length() == 1);
10374 Handle<Object> break_point_object_arg = args.at<Object>(0);
10375
10376 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010377 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010378
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010379 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010380}
10381
10382
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010383// Change the state of break on exceptions.
10384// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10385// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010386RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010387 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010388 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010389 RUNTIME_ASSERT(args[0]->IsNumber());
10390 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010391
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010392 // If the number doesn't match an enum value, the ChangeBreakOnException
10393 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010394 ExceptionBreakType type =
10395 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010396 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010397 isolate->debug()->ChangeBreakOnException(type, enable);
10398 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010399}
10400
10401
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010402// Returns the state of break on exceptions
10403// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010404RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010405 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010406 ASSERT(args.length() == 1);
10407 RUNTIME_ASSERT(args[0]->IsNumber());
10408
10409 ExceptionBreakType type =
10410 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010411 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010412 return Smi::FromInt(result);
10413}
10414
10415
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010416// Prepare for stepping
10417// args[0]: break id for checking execution state
10418// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010419// args[2]: number of times to perform the step, for step out it is the number
10420// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010421RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010422 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010423 ASSERT(args.length() == 3);
10424 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010425 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010426 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10427 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010428 if (!maybe_check->ToObject(&check)) return maybe_check;
10429 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010430 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010431 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010432 }
10433
10434 // Get the step action and check validity.
10435 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10436 if (step_action != StepIn &&
10437 step_action != StepNext &&
10438 step_action != StepOut &&
10439 step_action != StepInMin &&
10440 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010441 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010442 }
10443
10444 // Get the number of steps.
10445 int step_count = NumberToInt32(args[2]);
10446 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010447 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010448 }
10449
ager@chromium.orga1645e22009-09-09 19:27:10 +000010450 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010451 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010452
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010453 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010454 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10455 step_count);
10456 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010457}
10458
10459
10460// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010461RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010462 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010463 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010464 isolate->debug()->ClearStepping();
10465 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010466}
10467
10468
10469// Creates a copy of the with context chain. The copy of the context chain is
10470// is linked to the function context supplied.
10471static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10472 Handle<Context> function_context) {
10473 // At the bottom of the chain. Return the function context to link to.
10474 if (context_chain->is_function_context()) {
10475 return function_context;
10476 }
10477
10478 // Recursively copy the with contexts.
10479 Handle<Context> previous(context_chain->previous());
10480 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010481 Handle<Context> context = CopyWithContextChain(function_context, previous);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010482 return context->GetIsolate()->factory()->NewWithContext(
10483 context, extension, context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010484}
10485
10486
10487// Helper function to find or create the arguments object for
10488// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010489static Handle<Object> GetArgumentsObject(Isolate* isolate,
10490 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010491 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010492 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010493 const ScopeInfo<>* sinfo,
10494 Handle<Context> function_context) {
10495 // Try to find the value of 'arguments' to pass as parameter. If it is not
10496 // found (that is the debugged function does not reference 'arguments' and
10497 // does not support eval) then create an 'arguments' object.
10498 int index;
10499 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010500 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010501 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010502 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010503 }
10504 }
10505
10506 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010507 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10508 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010509 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010510 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010511 }
10512 }
10513
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010514 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010515 Handle<JSObject> arguments =
10516 isolate->factory()->NewArgumentsObject(function, length);
10517 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010518
10519 AssertNoAllocation no_gc;
10520 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010521 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010522 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010523 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010524 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010525 return arguments;
10526}
10527
10528
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010529static const char kSourceStr[] =
10530 "(function(arguments,__source__){return eval(__source__);})";
10531
10532
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010533// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010534// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010535// extension part has all the parameters and locals of the function on the
10536// stack frame. A function which calls eval with the code to evaluate is then
10537// compiled in this context and called in this context. As this context
10538// replaces the context of the function on the stack frame a new (empty)
10539// function is created as well to be used as the closure for the context.
10540// This function and the context acts as replacements for the function on the
10541// stack frame presenting the same view of the values of parameters and
10542// local variables as if the piece of JavaScript was evaluated at the point
10543// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010544RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010545 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010546
10547 // Check the execution state and decode arguments frame and source to be
10548 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010549 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010550 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010551 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10552 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010553 if (!maybe_check_result->ToObject(&check_result)) {
10554 return maybe_check_result;
10555 }
10556 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010557 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10558 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010559 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010560 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010561
10562 // Handle the processing of break.
10563 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010564
10565 // Get the frame where the debugging is performed.
10566 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010567 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010568 JavaScriptFrame* frame = it.frame();
10569 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010570 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010571 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010572
10573 // Traverse the saved contexts chain to find the active context for the
10574 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010575 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010576 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010577 save = save->prev();
10578 }
10579 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010580 SaveContext savex(isolate);
10581 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010582
10583 // Create the (empty) function replacing the function on the stack frame for
10584 // the purpose of evaluating in the context created below. It is important
10585 // that this function does not describe any parameters and local variables
10586 // in the context. If it does then this will cause problems with the lookup
10587 // in Context::Lookup, where context slots for parameters and local variables
10588 // are looked at before the extension object.
10589 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010590 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10591 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010592 go_between->set_context(function->context());
10593#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010594 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010595 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10596 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10597#endif
10598
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010599 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010600 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10601 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010602
10603 // Allocate a new context for the debug evaluation and set the extension
10604 // object build.
10605 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010606 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10607 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010608 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010609 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010610 Handle<Context> frame_context(Context::cast(frame->context()));
10611 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010612 context = CopyWithContextChain(frame_context, context);
10613
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010614 if (additional_context->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010615 context = isolate->factory()->NewWithContext(context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010616 Handle<JSObject>::cast(additional_context), false);
10617 }
10618
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010619 // Wrap the evaluation statement in a new function compiled in the newly
10620 // created context. The function has one parameter which has to be called
10621 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010622 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010623 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010624
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010625 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010626 isolate->factory()->NewStringFromAscii(
10627 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010628
10629 // Currently, the eval code will be executed in non-strict mode,
10630 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010631 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010632 Compiler::CompileEval(function_source,
10633 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010634 context->IsGlobalContext(),
10635 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010636 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010637 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010638 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010639
10640 // Invoke the result of the compilation to get the evaluation function.
10641 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010642 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010643 Handle<Object> evaluation_function =
10644 Execution::Call(compiled_function, receiver, 0, NULL,
10645 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010646 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010647
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010648 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
10649 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010650 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010651
10652 // Invoke the evaluation function and return the result.
10653 const int argc = 2;
10654 Object** argv[argc] = { arguments.location(),
10655 Handle<Object>::cast(source).location() };
10656 Handle<Object> result =
10657 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10658 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010659 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010660
10661 // Skip the global proxy as it has no properties and always delegates to the
10662 // real global object.
10663 if (result->IsJSGlobalProxy()) {
10664 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10665 }
10666
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010667 return *result;
10668}
10669
10670
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010671RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010672 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010673
10674 // Check the execution state and decode arguments frame and source to be
10675 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010676 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010677 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010678 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10679 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010680 if (!maybe_check_result->ToObject(&check_result)) {
10681 return maybe_check_result;
10682 }
10683 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010684 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010685 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010686 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010687
10688 // Handle the processing of break.
10689 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010690
10691 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010692 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010693 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010694 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010695 top = top->prev();
10696 }
10697 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010698 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010699 }
10700
10701 // Get the global context now set to the top context from before the
10702 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010703 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010704
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010705 bool is_global = true;
10706
10707 if (additional_context->IsJSObject()) {
10708 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010709 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
10710 isolate->factory()->empty_string(),
10711 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010712 go_between->set_context(*context);
10713 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010714 isolate->factory()->NewFunctionContext(
10715 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010716 context->set_extension(JSObject::cast(*additional_context));
10717 is_global = false;
10718 }
10719
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010720 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010721 // Currently, the eval code will be executed in non-strict mode,
10722 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010723 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010724 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010725 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010726 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010727 Handle<JSFunction>(
10728 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
10729 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010730
10731 // Invoke the result of the compilation to get the evaluation function.
10732 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010733 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010734 Handle<Object> result =
10735 Execution::Call(compiled_function, receiver, 0, NULL,
10736 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010737 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010738 return *result;
10739}
10740
10741
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010742RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010743 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010744 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010745
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010746 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010747 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010748
10749 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010750 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010751 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10752 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10753 // because using
10754 // instances->set(i, *GetScriptWrapper(script))
10755 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10756 // already have deferenced the instances handle.
10757 Handle<JSValue> wrapper = GetScriptWrapper(script);
10758 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010759 }
10760
10761 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010762 Handle<JSObject> result =
10763 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010764 Handle<JSArray>::cast(result)->SetContent(*instances);
10765 return *result;
10766}
10767
10768
10769// Helper function used by Runtime_DebugReferencedBy below.
10770static int DebugReferencedBy(JSObject* target,
10771 Object* instance_filter, int max_references,
10772 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010773 JSFunction* arguments_function) {
10774 NoHandleAllocation ha;
10775 AssertNoAllocation no_alloc;
10776
10777 // Iterate the heap.
10778 int count = 0;
10779 JSObject* last = NULL;
10780 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010781 HeapObject* heap_obj = NULL;
10782 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010783 (max_references == 0 || count < max_references)) {
10784 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010785 if (heap_obj->IsJSObject()) {
10786 // Skip context extension objects and argument arrays as these are
10787 // checked in the context of functions using them.
10788 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010789 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010790 obj->map()->constructor() == arguments_function) {
10791 continue;
10792 }
10793
10794 // Check if the JS object has a reference to the object looked for.
10795 if (obj->ReferencesObject(target)) {
10796 // Check instance filter if supplied. This is normally used to avoid
10797 // references from mirror objects (see Runtime_IsInPrototypeChain).
10798 if (!instance_filter->IsUndefined()) {
10799 Object* V = obj;
10800 while (true) {
10801 Object* prototype = V->GetPrototype();
10802 if (prototype->IsNull()) {
10803 break;
10804 }
10805 if (instance_filter == prototype) {
10806 obj = NULL; // Don't add this object.
10807 break;
10808 }
10809 V = prototype;
10810 }
10811 }
10812
10813 if (obj != NULL) {
10814 // Valid reference found add to instance array if supplied an update
10815 // count.
10816 if (instances != NULL && count < instances_size) {
10817 instances->set(count, obj);
10818 }
10819 last = obj;
10820 count++;
10821 }
10822 }
10823 }
10824 }
10825
10826 // Check for circular reference only. This can happen when the object is only
10827 // referenced from mirrors and has a circular reference in which case the
10828 // object is not really alive and would have been garbage collected if not
10829 // referenced from the mirror.
10830 if (count == 1 && last == target) {
10831 count = 0;
10832 }
10833
10834 // Return the number of referencing objects found.
10835 return count;
10836}
10837
10838
10839// Scan the heap for objects with direct references to an object
10840// args[0]: the object to find references to
10841// args[1]: constructor function for instances to exclude (Mirror)
10842// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010843RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010844 ASSERT(args.length() == 3);
10845
10846 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010847 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010848
10849 // Check parameters.
10850 CONVERT_CHECKED(JSObject, target, args[0]);
10851 Object* instance_filter = args[1];
10852 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10853 instance_filter->IsJSObject());
10854 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10855 RUNTIME_ASSERT(max_references >= 0);
10856
10857 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010858 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010859 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010860 JSFunction* arguments_function =
10861 JSFunction::cast(arguments_boilerplate->map()->constructor());
10862
10863 // Get the number of referencing objects.
10864 int count;
10865 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010866 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010867
10868 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010869 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010870 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010871 if (!maybe_object->ToObject(&object)) return maybe_object;
10872 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873 FixedArray* instances = FixedArray::cast(object);
10874
10875 // Fill the referencing objects.
10876 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010877 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010878
10879 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010880 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010881 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
10882 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010883 if (!maybe_result->ToObject(&result)) return maybe_result;
10884 }
10885 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010886 return result;
10887}
10888
10889
10890// Helper function used by Runtime_DebugConstructedBy below.
10891static int DebugConstructedBy(JSFunction* constructor, int max_references,
10892 FixedArray* instances, int instances_size) {
10893 AssertNoAllocation no_alloc;
10894
10895 // Iterate the heap.
10896 int count = 0;
10897 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010898 HeapObject* heap_obj = NULL;
10899 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010900 (max_references == 0 || count < max_references)) {
10901 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010902 if (heap_obj->IsJSObject()) {
10903 JSObject* obj = JSObject::cast(heap_obj);
10904 if (obj->map()->constructor() == constructor) {
10905 // Valid reference found add to instance array if supplied an update
10906 // count.
10907 if (instances != NULL && count < instances_size) {
10908 instances->set(count, obj);
10909 }
10910 count++;
10911 }
10912 }
10913 }
10914
10915 // Return the number of referencing objects found.
10916 return count;
10917}
10918
10919
10920// Scan the heap for objects constructed by a specific function.
10921// args[0]: the constructor to find instances of
10922// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010923RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010924 ASSERT(args.length() == 2);
10925
10926 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010927 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010928
10929 // Check parameters.
10930 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10931 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10932 RUNTIME_ASSERT(max_references >= 0);
10933
10934 // Get the number of referencing objects.
10935 int count;
10936 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10937
10938 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010939 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010940 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010941 if (!maybe_object->ToObject(&object)) return maybe_object;
10942 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010943 FixedArray* instances = FixedArray::cast(object);
10944
10945 // Fill the referencing objects.
10946 count = DebugConstructedBy(constructor, max_references, instances, count);
10947
10948 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010949 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010950 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
10951 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010952 if (!maybe_result->ToObject(&result)) return maybe_result;
10953 }
10954 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010955 return result;
10956}
10957
10958
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010959// Find the effective prototype object as returned by __proto__.
10960// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010961RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010962 ASSERT(args.length() == 1);
10963
10964 CONVERT_CHECKED(JSObject, obj, args[0]);
10965
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010966 // Use the __proto__ accessor.
10967 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010968}
10969
10970
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010971RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000010972 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010973 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010974 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010975}
10976
10977
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010978RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010979#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010980 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010981 ASSERT(args.length() == 1);
10982 // Get the function and make sure it is compiled.
10983 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010984 Handle<SharedFunctionInfo> shared(func->shared());
10985 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010986 return Failure::Exception();
10987 }
10988 func->code()->PrintLn();
10989#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010990 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010991}
ager@chromium.org9085a012009-05-11 19:22:57 +000010992
10993
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010994RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010995#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010996 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010997 ASSERT(args.length() == 1);
10998 // Get the function and make sure it is compiled.
10999 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011000 Handle<SharedFunctionInfo> shared(func->shared());
11001 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011002 return Failure::Exception();
11003 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011004 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011005#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011006 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011007}
11008
11009
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011010RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011011 NoHandleAllocation ha;
11012 ASSERT(args.length() == 1);
11013
11014 CONVERT_CHECKED(JSFunction, f, args[0]);
11015 return f->shared()->inferred_name();
11016}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011017
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011018
11019static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011020 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011021 AssertNoAllocation no_allocations;
11022
11023 int counter = 0;
11024 int buffer_size = buffer->length();
11025 HeapIterator iterator;
11026 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11027 ASSERT(obj != NULL);
11028 if (!obj->IsSharedFunctionInfo()) {
11029 continue;
11030 }
11031 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11032 if (shared->script() != script) {
11033 continue;
11034 }
11035 if (counter < buffer_size) {
11036 buffer->set(counter, shared);
11037 }
11038 counter++;
11039 }
11040 return counter;
11041}
11042
11043// For a script finds all SharedFunctionInfo's in the heap that points
11044// to this script. Returns JSArray of SharedFunctionInfo wrapped
11045// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011046RUNTIME_FUNCTION(MaybeObject*,
11047 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011048 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011049 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011050 CONVERT_CHECKED(JSValue, script_value, args[0]);
11051
11052 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11053
11054 const int kBufferSize = 32;
11055
11056 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011057 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011058 int number = FindSharedFunctionInfosForScript(*script, *array);
11059 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011060 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011061 FindSharedFunctionInfosForScript(*script, *array);
11062 }
11063
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011064 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011065 result->set_length(Smi::FromInt(number));
11066
11067 LiveEdit::WrapSharedFunctionInfos(result);
11068
11069 return *result;
11070}
11071
11072// For a script calculates compilation information about all its functions.
11073// The script source is explicitly specified by the second argument.
11074// The source of the actual script is not used, however it is important that
11075// all generated code keeps references to this particular instance of script.
11076// Returns a JSArray of compilation infos. The array is ordered so that
11077// each function with all its descendant is always stored in a continues range
11078// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011079RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011080 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011081 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011082 CONVERT_CHECKED(JSValue, script, args[0]);
11083 CONVERT_ARG_CHECKED(String, source, 1);
11084 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11085
11086 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11087
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011088 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011089 return Failure::Exception();
11090 }
11091
11092 return result;
11093}
11094
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011095// Changes the source of the script to a new_source.
11096// If old_script_name is provided (i.e. is a String), also creates a copy of
11097// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011098RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011099 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011100 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011101 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11102 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011103 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011104
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011105 CONVERT_CHECKED(Script, original_script_pointer,
11106 original_script_value->value());
11107 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011108
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011109 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11110 new_source,
11111 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011112
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011113 if (old_script->IsScript()) {
11114 Handle<Script> script_handle(Script::cast(old_script));
11115 return *(GetScriptWrapper(script_handle));
11116 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011117 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011118 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011119}
11120
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011121
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011122RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011123 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011124 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011125 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11126 return LiveEdit::FunctionSourceUpdated(shared_info);
11127}
11128
11129
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011130// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011131RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011132 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011133 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011134 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11135 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11136
ager@chromium.orgac091b72010-05-05 07:34:42 +000011137 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011138}
11139
11140// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011141RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011142 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011143 HandleScope scope(isolate);
11144 Handle<Object> function_object(args[0], isolate);
11145 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011146
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011147 if (function_object->IsJSValue()) {
11148 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11149 if (script_object->IsJSValue()) {
11150 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011151 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011152 }
11153
11154 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11155 } else {
11156 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11157 // and we check it in this function.
11158 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011159
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011160 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011161}
11162
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011163
11164// In a code of a parent function replaces original function as embedded object
11165// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011166RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011167 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011168 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011169
11170 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11171 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11172 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11173
11174 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11175 subst_wrapper);
11176
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011177 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011178}
11179
11180
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011181// Updates positions of a shared function info (first parameter) according
11182// to script source change. Text change is described in second parameter as
11183// array of groups of 3 numbers:
11184// (change_begin, change_end, change_end_new_position).
11185// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011186RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011187 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011188 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011189 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11190 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11191
ager@chromium.orgac091b72010-05-05 07:34:42 +000011192 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011193}
11194
11195
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011196// For array of SharedFunctionInfo's (each wrapped in JSValue)
11197// checks that none of them have activations on stacks (of any thread).
11198// Returns array of the same length with corresponding results of
11199// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011200RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011201 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011202 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011203 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011204 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011205
ager@chromium.org357bf652010-04-12 11:30:10 +000011206 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011207}
11208
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011209// Compares 2 strings line-by-line, then token-wise and returns diff in form
11210// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11211// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011212RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011213 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011214 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011215 CONVERT_ARG_CHECKED(String, s1, 0);
11216 CONVERT_ARG_CHECKED(String, s2, 1);
11217
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011218 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011219}
11220
11221
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011222// A testing entry. Returns statement position which is the closest to
11223// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011224RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011225 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011226 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011227 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11228 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11229
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011230 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011231
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011232 if (code->kind() != Code::FUNCTION &&
11233 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011234 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011235 }
11236
11237 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011238 int closest_pc = 0;
11239 int distance = kMaxInt;
11240 while (!it.done()) {
11241 int statement_position = static_cast<int>(it.rinfo()->data());
11242 // Check if this break point is closer that what was previously found.
11243 if (source_position <= statement_position &&
11244 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011245 closest_pc =
11246 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011247 distance = statement_position - source_position;
11248 // Check whether we can't get any closer.
11249 if (distance == 0) break;
11250 }
11251 it.next();
11252 }
11253
11254 return Smi::FromInt(closest_pc);
11255}
11256
11257
ager@chromium.org357bf652010-04-12 11:30:10 +000011258// Calls specified function with or without entering the debugger.
11259// This is used in unit tests to run code as if debugger is entered or simply
11260// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011261RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011262 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011263 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011264 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11265 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11266
11267 Handle<Object> result;
11268 bool pending_exception;
11269 {
11270 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011271 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011272 &pending_exception);
11273 } else {
11274 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011275 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011276 &pending_exception);
11277 }
11278 }
11279 if (!pending_exception) {
11280 return *result;
11281 } else {
11282 return Failure::Exception();
11283 }
11284}
11285
11286
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011287// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011288RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011289 CONVERT_CHECKED(String, arg, args[0]);
11290 SmartPointer<char> flags =
11291 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11292 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011293 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011294}
11295
11296
11297// Performs a GC.
11298// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011299RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011300 isolate->heap()->CollectAllGarbage(true);
11301 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011302}
11303
11304
11305// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011306RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011307 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011308 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011309 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011310 }
11311 return Smi::FromInt(usage);
11312}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011313
11314
11315// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011316RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011317#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011318 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011319#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011320 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011321#endif
11322}
11323
11324
11325// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011326RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011327#ifdef LIVE_OBJECT_LIST
11328 return LiveObjectList::Capture();
11329#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011330 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011331#endif
11332}
11333
11334
11335// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011336RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011337#ifdef LIVE_OBJECT_LIST
11338 CONVERT_SMI_CHECKED(id, args[0]);
11339 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011340 return success ? isolate->heap()->true_value() :
11341 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011342#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011343 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011344#endif
11345}
11346
11347
11348// Generates the response to a debugger request for a dump of the objects
11349// contained in the difference between the captured live object lists
11350// specified by id1 and id2.
11351// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11352// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011353RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011354#ifdef LIVE_OBJECT_LIST
11355 HandleScope scope;
11356 CONVERT_SMI_CHECKED(id1, args[0]);
11357 CONVERT_SMI_CHECKED(id2, args[1]);
11358 CONVERT_SMI_CHECKED(start, args[2]);
11359 CONVERT_SMI_CHECKED(count, args[3]);
11360 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11361 EnterDebugger enter_debugger;
11362 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11363#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011364 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011365#endif
11366}
11367
11368
11369// Gets the specified object as requested by the debugger.
11370// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011371RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011372#ifdef LIVE_OBJECT_LIST
11373 CONVERT_SMI_CHECKED(obj_id, args[0]);
11374 Object* result = LiveObjectList::GetObj(obj_id);
11375 return result;
11376#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011377 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011378#endif
11379}
11380
11381
11382// Gets the obj id for the specified address if valid.
11383// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011384RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011385#ifdef LIVE_OBJECT_LIST
11386 HandleScope scope;
11387 CONVERT_ARG_CHECKED(String, address, 0);
11388 Object* result = LiveObjectList::GetObjId(address);
11389 return result;
11390#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011391 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011392#endif
11393}
11394
11395
11396// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011397RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011398#ifdef LIVE_OBJECT_LIST
11399 HandleScope scope;
11400 CONVERT_SMI_CHECKED(obj_id, args[0]);
11401 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11402 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11403 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11404 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11405 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11406
11407 Handle<JSObject> instance_filter;
11408 if (args[1]->IsJSObject()) {
11409 instance_filter = args.at<JSObject>(1);
11410 }
11411 bool verbose = false;
11412 if (args[2]->IsBoolean()) {
11413 verbose = args[2]->IsTrue();
11414 }
11415 int start = 0;
11416 if (args[3]->IsSmi()) {
11417 start = Smi::cast(args[3])->value();
11418 }
11419 int limit = Smi::kMaxValue;
11420 if (args[4]->IsSmi()) {
11421 limit = Smi::cast(args[4])->value();
11422 }
11423
11424 return LiveObjectList::GetObjRetainers(obj_id,
11425 instance_filter,
11426 verbose,
11427 start,
11428 limit,
11429 filter_obj);
11430#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011431 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011432#endif
11433}
11434
11435
11436// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011437RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011438#ifdef LIVE_OBJECT_LIST
11439 HandleScope scope;
11440 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11441 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11442 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11443
11444 Handle<JSObject> instance_filter;
11445 if (args[2]->IsJSObject()) {
11446 instance_filter = args.at<JSObject>(2);
11447 }
11448
11449 Object* result =
11450 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11451 return result;
11452#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011453 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011454#endif
11455}
11456
11457
11458// Generates the response to a debugger request for a list of all
11459// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011460RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011461#ifdef LIVE_OBJECT_LIST
11462 CONVERT_SMI_CHECKED(start, args[0]);
11463 CONVERT_SMI_CHECKED(count, args[1]);
11464 return LiveObjectList::Info(start, count);
11465#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011466 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011467#endif
11468}
11469
11470
11471// Gets a dump of the specified object as requested by the debugger.
11472// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011473RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011474#ifdef LIVE_OBJECT_LIST
11475 HandleScope scope;
11476 CONVERT_SMI_CHECKED(obj_id, args[0]);
11477 Object* result = LiveObjectList::PrintObj(obj_id);
11478 return result;
11479#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011480 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011481#endif
11482}
11483
11484
11485// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011486RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011487#ifdef LIVE_OBJECT_LIST
11488 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011489 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011490#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011491 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011492#endif
11493}
11494
11495
11496// Generates the response to a debugger request for a summary of the types
11497// of objects in the difference between the captured live object lists
11498// specified by id1 and id2.
11499// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11500// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011501RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011502#ifdef LIVE_OBJECT_LIST
11503 HandleScope scope;
11504 CONVERT_SMI_CHECKED(id1, args[0]);
11505 CONVERT_SMI_CHECKED(id2, args[1]);
11506 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11507
11508 EnterDebugger enter_debugger;
11509 return LiveObjectList::Summarize(id1, id2, filter_obj);
11510#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011511 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011512#endif
11513}
11514
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011515#endif // ENABLE_DEBUGGER_SUPPORT
11516
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011517
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011518#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011519RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011520 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011521 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011522
11523 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011524 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11525 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011526 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011527}
11528
11529
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011530RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011531 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011532 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011533
11534 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011535 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11536 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011537 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011538}
11539
11540#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011541
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011542// Finds the script object from the script data. NOTE: This operation uses
11543// heap traversal to find the function generated for the source position
11544// for the requested break point. For lazily compiled functions several heap
11545// traversals might be required rendering this operation as a rather slow
11546// operation. However for setting break points which is normally done through
11547// some kind of user interaction the performance is not crucial.
11548static Handle<Object> Runtime_GetScriptFromScriptName(
11549 Handle<String> script_name) {
11550 // Scan the heap for Script objects to find the script with the requested
11551 // script data.
11552 Handle<Script> script;
11553 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011554 HeapObject* obj = NULL;
11555 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011556 // If a script is found check if it has the script data requested.
11557 if (obj->IsScript()) {
11558 if (Script::cast(obj)->name()->IsString()) {
11559 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11560 script = Handle<Script>(Script::cast(obj));
11561 }
11562 }
11563 }
11564 }
11565
11566 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011567 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011568
11569 // Return the script found.
11570 return GetScriptWrapper(script);
11571}
11572
11573
11574// Get the script object from script data. NOTE: Regarding performance
11575// see the NOTE for GetScriptFromScriptData.
11576// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011577RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011578 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011579
11580 ASSERT(args.length() == 1);
11581
11582 CONVERT_CHECKED(String, script_name, args[0]);
11583
11584 // Find the requested script.
11585 Handle<Object> result =
11586 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11587 return *result;
11588}
11589
11590
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011591// Determines whether the given stack frame should be displayed in
11592// a stack trace. The caller is the error constructor that asked
11593// for the stack trace to be collected. The first time a construct
11594// call to this function is encountered it is skipped. The seen_caller
11595// in/out parameter is used to remember if the caller has been seen
11596// yet.
11597static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11598 bool* seen_caller) {
11599 // Only display JS frames.
11600 if (!raw_frame->is_java_script())
11601 return false;
11602 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11603 Object* raw_fun = frame->function();
11604 // Not sure when this can happen but skip it just in case.
11605 if (!raw_fun->IsJSFunction())
11606 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011607 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011608 *seen_caller = true;
11609 return false;
11610 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011611 // Skip all frames until we've seen the caller. Also, skip the most
11612 // obvious builtin calls. Some builtin calls (such as Number.ADD
11613 // which is invoked using 'call') are very difficult to recognize
11614 // so we're leaving them in for now.
11615 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011616}
11617
11618
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011619// Collect the raw data for a stack trace. Returns an array of 4
11620// element segments each containing a receiver, function, code and
11621// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011622RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011623 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011624 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011625 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11626
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011627 HandleScope scope(isolate);
11628 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011629
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011630 limit = Max(limit, 0); // Ensure that limit is not negative.
11631 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011632 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011633 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011634
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011635 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011636 // If the caller parameter is a function we skip frames until we're
11637 // under it before starting to collect.
11638 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011639 int cursor = 0;
11640 int frames_seen = 0;
11641 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011642 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011643 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011644 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011645 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011646 // Set initial size to the maximum inlining level + 1 for the outermost
11647 // function.
11648 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011649 frame->Summarize(&frames);
11650 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011651 if (cursor + 4 > elements->length()) {
11652 int new_capacity = JSObject::NewElementsCapacity(elements->length());
11653 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011654 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011655 for (int i = 0; i < cursor; i++) {
11656 new_elements->set(i, elements->get(i));
11657 }
11658 elements = new_elements;
11659 }
11660 ASSERT(cursor + 4 <= elements->length());
11661
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011662 Handle<Object> recv = frames[i].receiver();
11663 Handle<JSFunction> fun = frames[i].function();
11664 Handle<Code> code = frames[i].code();
11665 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011666 elements->set(cursor++, *recv);
11667 elements->set(cursor++, *fun);
11668 elements->set(cursor++, *code);
11669 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011670 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011671 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011672 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011673 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011674 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011675 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011676 return *result;
11677}
11678
11679
ager@chromium.org3811b432009-10-28 14:53:37 +000011680// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011681RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011682 ASSERT_EQ(args.length(), 0);
11683
11684 NoHandleAllocation ha;
11685
11686 const char* version_string = v8::V8::GetVersion();
11687
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011688 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
11689 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000011690}
11691
11692
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011693RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011694 ASSERT(args.length() == 2);
11695 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11696 Smi::cast(args[1])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011697 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011698 OS::Abort();
11699 UNREACHABLE();
11700 return NULL;
11701}
11702
11703
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011704RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011705 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011706 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011707 Object* key = args[1];
11708
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011709 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011710 Object* o = cache->get(finger_index);
11711 if (o == key) {
11712 // The fastest case: hit the same place again.
11713 return cache->get(finger_index + 1);
11714 }
11715
11716 for (int i = finger_index - 2;
11717 i >= JSFunctionResultCache::kEntriesIndex;
11718 i -= 2) {
11719 o = cache->get(i);
11720 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011721 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011722 return cache->get(i + 1);
11723 }
11724 }
11725
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011726 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011727 ASSERT(size <= cache->length());
11728
11729 for (int i = size - 2; i > finger_index; i -= 2) {
11730 o = cache->get(i);
11731 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011732 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011733 return cache->get(i + 1);
11734 }
11735 }
11736
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011737 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011738 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011739
11740 Handle<JSFunctionResultCache> cache_handle(cache);
11741 Handle<Object> key_handle(key);
11742 Handle<Object> value;
11743 {
11744 Handle<JSFunction> factory(JSFunction::cast(
11745 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11746 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011747 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011748 // This handle is nor shared, nor used later, so it's safe.
11749 Object** argv[] = { key_handle.location() };
11750 bool pending_exception = false;
11751 value = Execution::Call(factory,
11752 receiver,
11753 1,
11754 argv,
11755 &pending_exception);
11756 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011757 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011758
11759#ifdef DEBUG
11760 cache_handle->JSFunctionResultCacheVerify();
11761#endif
11762
11763 // Function invocation may have cleared the cache. Reread all the data.
11764 finger_index = cache_handle->finger_index();
11765 size = cache_handle->size();
11766
11767 // If we have spare room, put new data into it, otherwise evict post finger
11768 // entry which is likely to be the least recently used.
11769 int index = -1;
11770 if (size < cache_handle->length()) {
11771 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
11772 index = size;
11773 } else {
11774 index = finger_index + JSFunctionResultCache::kEntrySize;
11775 if (index == cache_handle->length()) {
11776 index = JSFunctionResultCache::kEntriesIndex;
11777 }
11778 }
11779
11780 ASSERT(index % 2 == 0);
11781 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
11782 ASSERT(index < cache_handle->length());
11783
11784 cache_handle->set(index, *key_handle);
11785 cache_handle->set(index + 1, *value);
11786 cache_handle->set_finger_index(index);
11787
11788#ifdef DEBUG
11789 cache_handle->JSFunctionResultCacheVerify();
11790#endif
11791
11792 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011793}
11794
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011795
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011796RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011797 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011798 CONVERT_ARG_CHECKED(String, type, 0);
11799 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011800 return *isolate->factory()->NewJSMessageObject(
11801 type,
11802 arguments,
11803 0,
11804 0,
11805 isolate->factory()->undefined_value(),
11806 isolate->factory()->undefined_value(),
11807 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011808}
11809
11810
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011811RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011812 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11813 return message->type();
11814}
11815
11816
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011817RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011818 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11819 return message->arguments();
11820}
11821
11822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011823RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011824 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11825 return Smi::FromInt(message->start_position());
11826}
11827
11828
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011829RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011830 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11831 return message->script();
11832}
11833
11834
kasper.lund44510672008-07-25 07:37:58 +000011835#ifdef DEBUG
11836// ListNatives is ONLY used by the fuzz-natives.js in debug mode
11837// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011838RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000011839 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011840 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011841#define COUNT_ENTRY(Name, argc, ressize) + 1
11842 int entry_count = 0
11843 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
11844 INLINE_FUNCTION_LIST(COUNT_ENTRY)
11845 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
11846#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011847 Factory* factory = isolate->factory();
11848 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011849 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011850 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011851#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011852 { \
11853 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011854 Handle<String> name; \
11855 /* Inline runtime functions have an underscore in front of the name. */ \
11856 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011857 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011858 Vector<const char>("_" #Name, StrLength("_" #Name))); \
11859 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011860 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011861 Vector<const char>(#Name, StrLength(#Name))); \
11862 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011863 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011864 pair_elements->set(0, *name); \
11865 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011866 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011867 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011868 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011869 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011870 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011871 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011872 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011873 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011874#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011875 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011876 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011877 return *result;
11878}
kasper.lund44510672008-07-25 07:37:58 +000011879#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011880
11881
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011882RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011883 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011884 CONVERT_CHECKED(String, format, args[0]);
11885 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011886 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011887 LOGGER->LogRuntime(chars, elms);
11888 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011889}
11890
11891
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011892RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011893 UNREACHABLE(); // implemented as macro in the parser
11894 return NULL;
11895}
11896
11897
11898// ----------------------------------------------------------------------------
11899// Implementation of Runtime
11900
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011901#define F(name, number_of_args, result_size) \
11902 { Runtime::k##name, Runtime::RUNTIME, #name, \
11903 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011904
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011905
11906#define I(name, number_of_args, result_size) \
11907 { Runtime::kInline##name, Runtime::INLINE, \
11908 "_" #name, NULL, number_of_args, result_size },
11909
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011910static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011911 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011912 INLINE_FUNCTION_LIST(I)
11913 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011914};
11915
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011916
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011917MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
11918 Object* dictionary) {
11919 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011920 ASSERT(dictionary != NULL);
11921 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
11922 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011923 Object* name_symbol;
11924 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011925 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011926 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
11927 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011928 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011929 { MaybeObject* maybe_dictionary = string_dictionary->Add(
11930 String::cast(name_symbol),
11931 Smi::FromInt(i),
11932 PropertyDetails(NONE, NORMAL));
11933 if (!maybe_dictionary->ToObject(&dictionary)) {
11934 // Non-recoverable failure. Calling code must restart heap
11935 // initialization.
11936 return maybe_dictionary;
11937 }
11938 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011939 }
11940 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011941}
11942
11943
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011944const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
11945 Heap* heap = name->GetHeap();
11946 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011947 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011948 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011949 int function_index = Smi::cast(smi_index)->value();
11950 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011951 }
11952 return NULL;
11953}
11954
11955
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011956const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011957 return &(kIntrinsicFunctions[static_cast<int>(id)]);
11958}
11959
11960
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011961void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011962 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011963 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011964 if (failure->IsRetryAfterGC()) {
11965 // Try to do a garbage collection; ignore it if it fails. The C
11966 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011967 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011968 } else {
11969 // Handle last resort GC and make sure to allow future allocations
11970 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011971 isolate->counters()->gc_last_resort_from_js()->Increment();
11972 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011973 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011974}
11975
11976
11977} } // namespace v8::internal